聊聊dubbo的AwaitingNonWebApplicationListener

本文主要研究一下dubbo的AwaitingNonWebApplicationListener

AwaitingNonWebApplicationListener

dubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListener.java

public class AwaitingNonWebApplicationListener implements SmartApplicationListener {

    private static final String[] WEB_APPLICATION_CONTEXT_CLASSES = new String[]{
            "org.springframework.web.context.WebApplicationContext",
            "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext"
    };

    private static final Logger logger = LoggerFactory.getLogger(AwaitingNonWebApplicationListener.class);

    private static final Class<? extends ApplicationEvent>[] SUPPORTED_APPLICATION_EVENTS =
            of(ApplicationReadyEvent.class, ContextClosedEvent.class);

    private static final AtomicBoolean awaited = new AtomicBoolean(false);

    private static final Lock lock = new ReentrantLock();

    private static final Condition condition = lock.newCondition();

    private static final ExecutorService executorService = newSingleThreadExecutor();

    private static <T> T[] of(T... values) {
        return values;
    }

    static AtomicBoolean getAwaited() {
        return awaited;
    }

    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return containsElement(SUPPORTED_APPLICATION_EVENTS, eventType);
    }

    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        return true;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationReadyEvent) {
            onApplicationReadyEvent((ApplicationReadyEvent) event);
        } else if (event instanceof ContextClosedEvent) {
            onContextClosedEvent((ContextClosedEvent) event);
        }
    }

    @Override
    public int getOrder() {
        return LOWEST_PRECEDENCE;
    }

    protected void onApplicationReadyEvent(ApplicationReadyEvent event) {

        final ConfigurableApplicationContext applicationContext = event.getApplicationContext();

        if (!isRootApplicationContext(applicationContext) || isWebApplication(applicationContext)) {
            return;
        }

        await();
    }

    private boolean isRootApplicationContext(ApplicationContext applicationContext) {
        return applicationContext.getParent() == null;
    }

    private boolean isWebApplication(ApplicationContext applicationContext) {
        boolean webApplication = false;
        for (String contextClass : WEB_APPLICATION_CONTEXT_CLASSES) {
            if (isAssignable(contextClass, applicationContext.getClass(), applicationContext.getClassLoader())) {
                webApplication = true;
                break;
            }
        }
        return webApplication;
    }

    private static boolean isAssignable(String target, Class<?> type, ClassLoader classLoader) {
        try {
            return ClassUtils.resolveClassName(target, classLoader).isAssignableFrom(type);
        } catch (Throwable ex) {
            return false;
        }
    }

    protected void onContextClosedEvent(ContextClosedEvent event) {
        release();
        shutdown();
    }

    protected void await() {

        // has been waited, return immediately
        if (awaited.get()) {
            return;
        }

        if (!executorService.isShutdown()) {
            executorService.execute(() -> executeMutually(() -> {
                while (!awaited.get()) {
                    if (logger.isInfoEnabled()) {
                        logger.info(" [Dubbo] Current Spring Boot Application is await...");
                    }
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }));
        }
    }

    protected void release() {
        executeMutually(() -> {
            while (awaited.compareAndSet(false, true)) {
                if (logger.isInfoEnabled()) {
                    logger.info(" [Dubbo] Current Spring Boot Application is about to shutdown...");
                }
                condition.signalAll();
            }
        });
    }

    private void shutdown() {
        if (!executorService.isShutdown()) {
            // Shutdown executorService
            executorService.shutdown();
        }
    }

    private void executeMutually(Runnable runnable) {
        try {
            lock.lock();
            runnable.run();
        } finally {
            lock.unlock();
        }
    }
}
  • AwaitingNonWebApplicationListener实现了SmartApplicationListener接口,其supportsEventType支持ApplicationReadyEvent.class, ContextClosedEvent.class
  • onApplicationEvent判断是ApplicationReadyEvent时执行onApplicationReadyEvent方法;判断是ContextClosedEvent时,执行onContextClosedEvent方法
  • onApplicationReadyEvent对于rootApplicationContext或者是nonWebApplicationContext执行await方法,该方法会注册一个异步线程去执行condition.await();onContextClosedEvent则执行release及shutdown方法,release方法会更新awaited为true,然后执行condition.signalAll(),shutdown方法则关闭executorService

AwaitingNonWebApplicationListenerTest

dubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListenerTest.java

public class AwaitingNonWebApplicationListenerTest {

    @Test
    public void init() {
        AtomicBoolean awaited = AwaitingNonWebApplicationListener.getAwaited();
        awaited.set(false);

    }

    @Test
    public void testSingleContextNonWebApplication() {
        new SpringApplicationBuilder(Object.class)
                .web(false)
                .run().close();
        AtomicBoolean awaited = AwaitingNonWebApplicationListener.getAwaited();
        Assert.assertTrue(awaited.get());
    }

    @Test
    public void testMultipleContextNonWebApplication() {
        new SpringApplicationBuilder(Object.class)
                .parent(Object.class)
                .web(false)
                .run().close();
        AtomicBoolean awaited = AwaitingNonWebApplicationListener.getAwaited();
        Assert.assertTrue(awaited.get());
    }

}
  • AwaitingNonWebApplicationListenerTest验证了SingleContextNonWebApplication及MultipleContextNonWebApplication

小结

  • AwaitingNonWebApplicationListener实现了SmartApplicationListener接口,其supportsEventType支持ApplicationReadyEvent.class, ContextClosedEvent.class
  • onApplicationEvent判断是ApplicationReadyEvent时执行onApplicationReadyEvent方法;判断是ContextClosedEvent时,执行onContextClosedEvent方法
  • onApplicationReadyEvent对于rootApplicationContext或者是nonWebApplicationContext执行await方法,该方法会注册一个异步线程去执行condition.await();onContextClosedEvent则执行release及shutdown方法,release方法会更新awaited为true,然后执行condition.signalAll(),shutdown方法则关闭executorService

doc

  • AwaitingNonWebApplicationListener

本文分享自微信公众号 - 码匠的流水账(geek_luandun)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏海仔技术驿站

java基础第一篇

对于Java程序开发而言,主要会使用JDK的两个命令:javac.exe、java.exe。路径:C:\Java\jdk 1.7.0 _09\bin。但是这些命...

9340
来自专栏海仔技术驿站

当构造方法参数过多时使用builder模式

静态工厂和构造方法都有一个限制:它们不能很好地扩展到很多可选参数的情景。请考虑一个代表包装食品上的营养成分标签的例子。这些标签有几个必需的属性——每次建议的摄入...

14330
来自专栏海仔技术驿站

并发编程

线程安全 线程安全概念 : 当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的. ...

7130
来自专栏挨踢小子部落阁

全面理解Javascript闭包和闭包的几种写法及用途

好久没有写博客了,过了一个十一长假都变懒了,今天总算是恢复状态了。好了,进入正题,今天来说一说javascript里面的闭包吧!本篇博客主要讲一些实用的东西,...

6330
来自专栏海仔技术驿站

设计模式

静态内部类实现方式(也是一种赖加载方式) public class SingletonDemo04 { private static class Singl...

11740
来自专栏海仔技术驿站

Java程序员需要突破的技术要点

15440
来自专栏海仔技术驿站

理解线程池,看这篇足够了。

28950
来自专栏海仔技术驿站

最全的Spring注解详解

@Configuration : 配置类 == 配置文件,告诉Spring这是一个配置类 @ComponentScan(value="com.atguigu"...

9740
来自专栏海仔技术驿站

1. 考虑使用静态工厂方法替代构造方法

一个类允许客户端获取其实例的传统方式是提供一个公共构造方法。其实还有另一种技术应该成为每个程序员工具箱的一部分。一个类可以提供一个公共静态工厂方...

8530
来自专栏海仔技术驿站

java基础第二篇

1.应用场景:判断四季(春夏秋冬),判断星期,根据用户的选择,进行对应的操作

7420

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励