1. 程式人生 > 程式設計 >聊聊dubbo的AwaitingNonWebApplicationListener

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