springboot shutdown(停机)

springboot shutdown(停机)

工作中还没有使用过springboot搭建分布式服务。只是通过springboot搭建了一个简单的web工程,跑一些定时任务。所以不清楚springboot集群是如何部署和启停应用的。因为某些原因,工作中不能直接使用springboot打包成jar形式发布。最终决定自己写打包脚本,打包zip(tar.gz),并编写启动和停止脚本。(见文章《springboot打包成zip部署,并实现优雅停机》《springboot 启动脚本优化》

问题

那篇文章中通过springboot提供的应用监控插件,可以实现停机服务。但是有个问题,停机请求的url是写在stop.sh脚本的。如果应用部署的的配置调整了端口号,这样stop.sh脚本也要调整。现在因为单机部署还是没有什么问题,后面如果开始集群部署,肯定会引起很多麻烦。

思路

这里就想到了tomcat的启动和停止原理。

tomcat

tomcat启动时读取server.xml配置,同时监听一个端口,用于接收停机指令,一般默认是8005。当我们执行shutdown.sh时,执行同样的代码,但是会传入shutdown的参数,同样读取server.xml配置,根据配置的端口,发送shutdown指令,这样启动的服务就收到了停机指令,就开始停机操作。通过启动和停机都读取同一份配置文件,避免启动和停机需要维护两份配置的问题。

springboot

鉴于tomcat的启停原理,如果我停机的java代码中也能读取springboot的配置文件,获取应用的端口信息,再根据这个端口信息去发送停机请求。这样就可以避免修改stop.sh脚本。所以最重要的是如何自己读取springboot的配置文件。

改造

因为重点是读取springboot的配置,项目采用的是yml形式配置,一开始想到的是自己解析yml,但是出现了问题。项目采用application-dev.yml、application-test.yml等区分不同环境配置。我需要先解析application.yml配置,再根据spring.profiles.active配置读取对应配置文件。这样是不是太麻烦了呢?这个工作springboot不是已经做了一遍了吗?我是不是可以直接拿springboot解析配置文件的代码直接使用呢?

带着这样的疑问,我决定寻找一些springboot读取配置文件的原理。最后找到了这篇文章Spring Boot源码分析-配置文件加载。文中用的springboot版本是Spring Boot 2.1.0.RELEASE。我用的是Spring Boot 2.0.4.RELEASE,刚好可以借鉴一下。

具体springboot如何读取配置文件,文章中已经写的很清楚了。这里就不复述了。直接贴一下改造后的Shutdown类。

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.util.StringUtils;

import java.io.IOException;

/**
 * 应用关闭入口
 *
 * @author dingzg
 */
public class Shutdown extends ConfigFileApplicationListener {

    private static final Logger log = LoggerFactory.getLogger(Shutdown.class);

    public static void main(String[] args) {
        String url = "http://127.0.0.1:%s/actuator/shutdown";
        Shutdown shutdown = new Shutdown();
        ConfigurableEnvironment environment = shutdown.load();
        String port = environment.getProperty("management.server.port");
        if (StringUtils.isEmpty(port)) {
            port = environment.getProperty("server.port");
        }
        url = String.format(url, port);
        log.info("shutdown url = {}", url);
        HttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        try {
            HttpResponse httpResponse = httpClient.execute(httpPost);
            String strResult = EntityUtils.toString(httpResponse.getEntity());
            log.info("response = {}", strResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取springboot配置信息
     * @return
     */
    public ConfigurableEnvironment load() {
        ConfigurableEnvironment environment = new StandardEnvironment();
        super.addPropertySources(environment, new DefaultResourceLoader());
        return environment;
    }
}
原文地址:https://www.cnblogs.com/jimmyfan/p/13186047.html