|
20 | 20 | import org.slf4j.LoggerFactory;
|
21 | 21 | import org.springframework.boot.SpringApplication;
|
22 | 22 | import org.springframework.boot.context.event.ApplicationReadyEvent;
|
| 23 | +import org.springframework.context.ApplicationEvent; |
23 | 24 | import org.springframework.context.ApplicationListener;
|
| 25 | +import org.springframework.context.event.ContextClosedEvent; |
| 26 | +import org.springframework.context.event.SmartApplicationListener; |
| 27 | +import org.springframework.util.ObjectUtils; |
24 | 28 |
|
25 | 29 | import java.util.concurrent.ExecutorService;
|
26 | 30 | import java.util.concurrent.Executors;
|
27 | 31 | import java.util.concurrent.atomic.AtomicBoolean;
|
| 32 | +import java.util.concurrent.locks.Condition; |
| 33 | +import java.util.concurrent.locks.Lock; |
| 34 | +import java.util.concurrent.locks.ReentrantLock; |
28 | 35 |
|
29 | 36 | /**
|
30 | 37 | * Awaiting Non-Web Spring Boot {@link ApplicationListener}
|
31 | 38 | *
|
32 |
| - * @author <a href="mailto:[email protected]">Mercy</a> |
33 | 39 | * @since 0.1.1
|
34 | 40 | */
|
35 |
| -public class AwaitingNonWebApplicationListener implements ApplicationListener<ApplicationReadyEvent> { |
| 41 | +public class AwaitingNonWebApplicationListener implements SmartApplicationListener { |
36 | 42 |
|
37 | 43 | private static final Logger logger = LoggerFactory.getLogger(AwaitingNonWebApplicationListener.class);
|
38 | 44 |
|
39 |
| - private static final ExecutorService executorService = Executors.newSingleThreadExecutor(); |
40 |
| - |
41 |
| - private static final AtomicBoolean shutdownHookRegistered = new AtomicBoolean(false); |
| 45 | + private static final Class<? extends ApplicationEvent>[] SUPPORTED_APPLICATION_EVENTS = |
| 46 | + of(ApplicationReadyEvent.class, ContextClosedEvent.class); |
42 | 47 |
|
43 | 48 | private static final AtomicBoolean awaited = new AtomicBoolean(false);
|
44 | 49 |
|
| 50 | + private final Lock lock = new ReentrantLock(); |
| 51 | + |
| 52 | + private final Condition condition = lock.newCondition(); |
| 53 | + |
| 54 | + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); |
| 55 | + |
| 56 | + private static <T> T[] of(T... values) { |
| 57 | + return values; |
| 58 | + } |
| 59 | + |
| 60 | + @Override |
| 61 | + public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { |
| 62 | + return ObjectUtils.containsElement(SUPPORTED_APPLICATION_EVENTS, eventType); |
| 63 | + } |
| 64 | + |
| 65 | + @Override |
| 66 | + public boolean supportsSourceType(Class<?> sourceType) { |
| 67 | + return true; |
| 68 | + } |
| 69 | + |
45 | 70 | @Override
|
46 |
| - public void onApplicationEvent(ApplicationReadyEvent event) { |
| 71 | + public void onApplicationEvent(ApplicationEvent event) { |
| 72 | + if (event instanceof ApplicationReadyEvent) { |
| 73 | + onApplicationReadyEvent((ApplicationReadyEvent) event); |
| 74 | + } else if (event instanceof ContextClosedEvent) { |
| 75 | + onContextClosedEvent((ContextClosedEvent) event); |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + @Override |
| 80 | + public int getOrder() { |
| 81 | + return LOWEST_PRECEDENCE; |
| 82 | + } |
| 83 | + |
| 84 | + protected void onApplicationReadyEvent(ApplicationReadyEvent event) { |
47 | 85 |
|
48 | 86 | final SpringApplication springApplication = event.getSpringApplication();
|
49 | 87 |
|
50 | 88 | if (springApplication.isWebEnvironment()) {
|
51 | 89 | return;
|
52 | 90 | }
|
53 | 91 |
|
| 92 | + await(); |
| 93 | + |
| 94 | + } |
| 95 | + |
| 96 | + protected void onContextClosedEvent(ContextClosedEvent event) { |
| 97 | + release(); |
| 98 | + shutdown(); |
| 99 | + } |
| 100 | + |
| 101 | + protected void await() { |
| 102 | + |
| 103 | + // has been waited, return immediately |
| 104 | + if (awaited.get()) { |
| 105 | + return; |
| 106 | + } |
| 107 | + |
54 | 108 | executorService.execute(new Runnable() {
|
55 | 109 | @Override
|
56 | 110 | public void run() {
|
57 |
| - |
58 |
| - synchronized (springApplication) { |
59 |
| - if (logger.isInfoEnabled()) { |
60 |
| - logger.info(" [Dubbo] Current Spring Boot Application is await..."); |
61 |
| - } |
62 |
| - while (!awaited.get()) { |
63 |
| - try { |
64 |
| - springApplication.wait(); |
65 |
| - } catch (InterruptedException e) { |
66 |
| - Thread.currentThread().interrupt(); |
| 111 | + executeMutually(new Runnable() { |
| 112 | + @Override |
| 113 | + public void run() { |
| 114 | + while (!awaited.get()) { |
| 115 | + if (logger.isInfoEnabled()) { |
| 116 | + logger.info(" [Dubbo] Current Spring Boot Application is await..."); |
| 117 | + } |
| 118 | + try { |
| 119 | + condition.await(); |
| 120 | + } catch (InterruptedException e) { |
| 121 | + Thread.currentThread().interrupt(); |
| 122 | + } |
67 | 123 | }
|
68 | 124 | }
|
69 |
| - } |
| 125 | + }); |
70 | 126 | }
|
71 | 127 | });
|
| 128 | + } |
72 | 129 |
|
73 |
| - // register ShutdownHook |
74 |
| - if (shutdownHookRegistered.compareAndSet(false, true)) { |
75 |
| - registerShutdownHook(new Thread(new Runnable() { |
76 |
| - @Override |
77 |
| - public void run() { |
78 |
| - synchronized (springApplication) { |
79 |
| - if (awaited.compareAndSet(false, true)) { |
80 |
| - springApplication.notifyAll(); |
81 |
| - if (logger.isInfoEnabled()) { |
82 |
| - logger.info(" [Dubbo] Current Spring Boot Application is about to shutdown..."); |
83 |
| - } |
84 |
| - // Shutdown executorService |
85 |
| - executorService.shutdown(); |
86 |
| - } |
| 130 | + protected void release() { |
| 131 | + executeMutually(new Runnable() { |
| 132 | + @Override |
| 133 | + public void run() { |
| 134 | + while (awaited.compareAndSet(false, true)) { |
| 135 | + if (logger.isInfoEnabled()) { |
| 136 | + logger.info(" [Dubbo] Current Spring Boot Application is about to shutdown..."); |
87 | 137 | }
|
| 138 | + condition.signalAll(); |
88 | 139 | }
|
89 |
| - })); |
| 140 | + } |
| 141 | + }); |
| 142 | + } |
| 143 | + |
| 144 | + private void shutdown() { |
| 145 | + if (!executorService.isShutdown()) { |
| 146 | + // Shutdown executorService |
| 147 | + executorService.shutdown(); |
| 148 | + } |
| 149 | + } |
| 150 | + |
| 151 | + private void executeMutually(Runnable runnable) { |
| 152 | + try { |
| 153 | + lock.lock(); |
| 154 | + runnable.run(); |
| 155 | + } finally { |
| 156 | + lock.unlock(); |
90 | 157 | }
|
91 | 158 | }
|
92 | 159 |
|
93 |
| - private void registerShutdownHook(Thread thread) { |
94 |
| - Runtime.getRuntime().addShutdownHook(thread); |
| 160 | + static AtomicBoolean getAwaited() { |
| 161 | + return awaited; |
95 | 162 | }
|
96 | 163 | }
|
0 commit comments