<p dir="auto">-关于2.6.3release版本优雅停机问题，之前我在社区也发提出的issue中于开发交流过，发现依然存在问题。</p>
<ol dir="auto">
<li>
<p dir="auto">框架的停机hook和spring的停机hook同时触发，导致服务的实现类中无法获取业务bean，导致服务无法正确完成。（因为spring context先于框架close了）<br>
场景一：Springboot+innerTomcat<br>
<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/SpringBootApplication/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/SpringBootApplication">@SpringBootApplication</a><br>
@ComponetScan<br>
@ImportResource({"classpath:/META-INF/spring/dubbo*.xml"})<br>
public class GatewayApplication {<br>
public static void main(String[] args) {<br>
SpringApplication.run(GatewayApplication.class, args);<br>
System.in.read();<br>
//模拟停机<br>
System.exit(0);<br>
}<br>
}<br>
场景二：<br>
public static void main(String[] args) {<br>
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(classpath:/META-INF/spring/dubbo*.xml);<br>
ctx.registerShutdownHook();<br>
ctx.start();<br>
}</p>
</li>
<li>
<p dir="auto">我们分析了下2.6.3停机代码，针对spring容器需要关闭dubbo默认hook，通过spring的停机hook触发close事件listener来停机。初始化DubboApplicationListener目前只针对Main方法和Spring+web.xml方式。个人觉得DubboApplicationListener思路是对的，但是需要针对不同spring使用场景，不能总体覆盖。个人觉得DubboApplicationContextInitializer设计就有点别扭。</p>
</li>
<li>
<p dir="auto">建议：针对Spring容器优雅停机，我们建议将spring close事件监听逻辑移到ApplicationConfig中，并在ApplicationConfig中注销默认停机hook，注册spring 停机hook。这样做的好处就是，如果框架是基于spring容器，可以一刀切的方式实现hook的管理，完全依赖spirng管理停机，使用者仅需要关系spring生命周期。核心修改如下：<br>
ApplicationConfig implments ApplicationContextWare, ApplicationListener{<br>
public void onApplicationEvent(ContextClosedEvent event){<br>
DubboShutdownHook.getDubboShutDownHook().destroyAll();<br>
}</p>
<p dir="auto">public void setApplicationContext(ApplicationContext ctx){<br>
//注销dubbohook，将removeShutdownHook从DubboBootstrap中迁移到DubboShutdownHook中<br>
DubboShutdownHook.removeShutdownHook();<br>
//注册spring hook<br>
ctx.registerShutdownHook();<br>
}<br>
}</p>
</li>
</ol>
<p dir="auto">4.我们应用在实际使用过程中碰到很多停机问题，我们也针对性的对框架优雅停机尝试研究和优化，个人对dubbo代码理解有限，恳请指正。</p>
<p dir="auto">我们在测试及生产环境下总结目前Dubbo优雅停机问题存在几个问题：<br>
[1]Spring可能先于框架关闭，导致业务服务无法正确执行完成；<br>
[2]tomcat+spring场景，中间件停机可能会导致class被回收，导致log日志无法输出，甚至报class not found；<br>
[3]如果存在多个hook，如spring本身有hook，无法保证hook执行顺序；<br>
[4]zk在大数据量同步通知下延迟严重，导致注销后仍有请求（目前版本简单sleep了一下）；<br>
[5]停机时间无法设置，官方关于“停机设置标志位”的描述有误。</p>
<p dir="auto">综上所述，我们的优化作法是将框架的优雅停机委托给Spring管理，通过监听Spring的close事件触发停机，这样做有两个好处：(1)保证框架停机优于Spring关闭;(2)应用用起来简单，只需要维护Spring生命周期；(3)相对于hook方式，主动调用停机接口更让人放心。</p>