聊聊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

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏跨平台全栈俱乐部

如何从JavaScript跨越到TypeScript [基础进阶知识点]

一致,都会导致报错。 建议使用npm 全局安装typeScript 然后使用 tsc *.ts 进行编译TS文件

11820
来自专栏Vue源码 & 前端进阶体系

【npm】简化本地文件引用路径

2、难以维护,如果我文件路径移动了一下...所有引用的地方都要改 就算你会全局替换,摸摸你的良心说,你心里不慌吗,反正我慌得一匹

45140
来自专栏跨平台全栈俱乐部

React的移动端和PC端生态圈的使用汇总

由于React的生态极为庞大,本文内容部分来自一些别人的汇总,至于原文只要还是能找到的,我都会贴上地址,谢谢前期贡献的作者,如果有没有被汇总到的,欢迎在下面补充...

12140
来自专栏跨平台全栈俱乐部

如何优化你的超大型React应用

新,会自上而下逐渐刷新整个子孙组件,这样性能损耗重复渲染就会多出很多,所以我们不仅要单一数据来源控制组件刷新,偶尔还需要在shouldComponentUpda...

26540
来自专栏web前端基地

Ajax第一节

异步: 不受当前任务的影响,两件事情同时进行,做一件事情时,不影响另一件事情的进行。

14020
来自专栏Vue源码 & 前端进阶体系

【怕啥弄啥系列】总要爱上它《正则》 - 高级

正则默认是贪婪匹配的,为什么一开始设计默认是贪婪呢?我估计,是设计者想设计得人性化一些

4730
来自专栏猿湿Xoong

代码之美,正则之道

从1956年至今,正则表达式活跃了半个多世纪,其热度依然不减,可见技术半衰期之长,因此,学习正则,不但重要,且受益漫长。

18320
来自专栏前端小而全的知识归纳

Vue,React,微信小程序,快应用,TS 和 Koa 一把梭

话不多说,源码地址:Vue,React,微信小程序,快应用,TS 和 Koa 地址,欢迎 star 项目目录:

16020
来自专栏Golang开发

JavaScrip概述

JavaScript 是一种运行在 客户端 的 解释性语言 网页三部分 HTML:控制网页的 结构 CSS:控制网页的 样式 JavaScript:控...

5730
来自专栏web前端基地

Ajax第三节

举例来说,这个网址http://www.example.com/dir/page.html协议是http://,

8020

扫码关注云+社区

领取腾讯云代金券

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