聊聊dubbo的AwaitingNonWebApplicationListener
阿新 • • 發佈:2019-12-31
序
本文主要研究一下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