序
本文主要研究一下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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。