Motan中很多地方用了线程池,有一些还是按一定频率一直在run的任务,比如心跳、Failback机制中的一些重试线程。这样会有一个问题,当把应用部署在Tomcat中的时候,用shutdown.sh关闭Tomcat的时候,这些线程池就关不掉,导致通过只能kill进程的方式来关闭。
在 0.3.1 中,Motan 实现了 ServletContextListener 接口和 ShutdownHook,在创建任务的时候,会去 ShutdownHook 中注册, 当 Context 关闭的时候,会通知该 Listener,然后该 Listener 就会去 shutdown 已经注册的这些任务。
1 2 3 4 5 6
| public class ShutDownHookListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent sce) { ShutDownHook.runHook(true); } }
|
当然,这个Listener是需要用户在web.xml中配置的,
1 2 3
| <listener> <listener-class>com.weibo.api.motan.closable.ShutDownHookListener</listener-class> </listener>
|
我可是看过 Tomcat 源码的人,看下 Tomcat 关闭过程中是如何处理的。首先,ServletContextListener 的通知当然应该在 StandardContext 中做,在 stopInternal() 中会调用 listenerStop(),这里会遍历所有监听器,如果是 ServletContextListener,则通知他们 context 销毁事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public boolean listenerStop() { Object listeners[] = getApplicationLifecycleListeners(); for (int i = 0; i < listeners.length; i++) { int j = (listeners.length - 1) - i; if (listeners[j] == null) continue; if (listeners[j] instanceof ServletContextListener) { ServletContextListener listener = (ServletContextListener) listeners[j]; try { fireContainerEvent("beforeContextDestroyed", listener); if (noPluggabilityListeners.contains(listener)) { listener.contextDestroyed(tldEvent); } else { listener.contextDestroyed(event); } fireContainerEvent("afterContextDestroyed", listener); } catch (Throwable t) { ... } } .... } }
|
.
以上皆是阅读源码 https://github.com/weibocom/motan (tag 0.3.1)所得,文中贴的代码或配置有所删减