美文网首页javaee
分析SpringBoot Actuator优雅停机自定义容器重启

分析SpringBoot Actuator优雅停机自定义容器重启

作者: Alex的IT生涯 | 来源:发表于2017-04-23 18:32 被阅读3603次

    最近在研究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<Endpoint>集合中。这样就以Mvc的方式暴露出来。

    以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来进行重启应用了。

    如果觉得我的文章对您有用,请关注我的微信公众号。长按图片识别二维码点击关注即可。

    @程序员

    相关文章

      网友评论

        本文标题:分析SpringBoot Actuator优雅停机自定义容器重启

        本文链接:https://www.haomeiwen.com/subject/hirjzttx.html