最近在研究SpringBoot Actuator,发现其提供了一个很特殊的功能,可以进行优雅停机,用户只需要引入SpringBoot Actuator,然后在application.properties中将endpoints.shutdown.enabled=true开启即可。然后我们只需要使用http post提交方式调用host:port/shutdown就可以实现优雅停机。那么SpringBoot是怎么做到的呢,于是便好奇地开启了源码阅读。
SpringBoot中每个请求/info,/health都是通过Endpoint的invoke方法来处理的,他将请求委托给了MvcEndpoint来进行处理。简单情况下,我们要自定义Endpoint只需要实现Endpoint并将其注入到spring上下文即可。SpringBoot是通过EndpointAutoConfiguration来注入组件的。但是如果我们要以Mvc的方式来注入就需要实现MvcEndpoint了,然后通过EndpointWebMvcManagementContextConfiguration来进行注入。最终通过重写了SpringMVC的RequestHandlerMapping的类EndpointHandlerMapping来对MvcEndpoint进行注册。所有的Actuator MvcEndpoint都是通过EndpointHandlerMapping的registerHandlerMethod来进行注册的。注册后就保存在EndpointHandlerMapping类的Set
以SpringBoot的优雅停机Shutdown endpoint为例:
至此表面ShutdownEndpoint是一个普通的Endpoint组件,我们将其注入spring上下文后就可以通过get方式调用了。但是根据官方文档他只能通过Post方式调用。原来其定义了一个ShutdownMvcEndpoint并限制了Post方式,参见下图:
然后通过EndpointWebMvcManagementContextConfiguration来进行注入:
那么我们现在来实现一个容器重启的ReloadEndpoint就很简单了。
首先自定义ReloadEndpoint
注意其核心逻辑先将SpringContext上下文stop然后再start
再在application.properties中将reload enabled: endpoints.reload.enabled=true
现在我们将其引入上下文就可以get调用了
@Bean
publicReloadEndpointreloadEndpoint(){
return newReloadEndpoint();
}
但是如果要使用post方式就需要增加MvcEndpoint了。
public class ReloadMvcEndpoint extends EndpointMvcAdapter {
publicReloadMvcEndpoint(ReloadEndpoint delegate) {
super(delegate);
}
@PostMapping(produces= { ActuatorMediaTypes.APPLICATION_ACTUATOR_V1_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE})
@ResponseBody
@Override
publicObjectinvoke() {
if(!getDelegate().isEnabled()) {
return newResponseEntity>(
Collections.singletonMap("message","This endpoint is disabled"),
HttpStatus.NOT_FOUND);
}
return super.invoke();
}
}
然后将其以Mvc方式暴露出去
@Bean
@ConditionalOnBean(ReloadEndpoint.class)
@ConditionalOnEnabledEndpoint(value="reload",enabledByDefault=false)
public ReloadMvcEndpoint reloadMvcEndpoint(ReloadEndpoint delegate) {
return newReloadMvcEndpoint(delegate);
}
通过页面Get方式调用会报错:
通过post方式调用即可成功,见日志:
至此一个自定义endpoint就完成了,假如我们监控到某台机器很耗内存,我们就可以通过host:port/reload来进行重启应用了。
如果觉得我的文章对您有用,请关注我的微信公众号。长按图片识别二维码点击关注即可。