工作中还没有使用过springboot搭建分布式服务。只是通过springboot搭建了一个简单的web工程,跑一些定时任务。所以不清楚springboot集群是如何部署和启停应用的。因为某些原因,工作中不能直接使用springboot打包成jar形式发布。最终决定自己写打包脚本,打包zip(tar.gz),并编写启动和停止脚本。(见另一篇文章《springboot打包成zip部署,并实现优雅停机》)
那篇文章中通过springboot提供的应用监控插件,可以实现停机服务。但是有个问题,停机请求的url是写在stop.sh脚本的。如果应用部署的的配置调整了端口号,这样stop.sh脚本也要调整。现在因为单机部署还是没有什么问题,后面如果开始集群部署,肯定会引起很多麻烦。
这里就想到了tomcat的启动和停止原理。
tomcat启动时读取server.xml配置,同时监听一个端口,用于接收停机指令,一般默认是8005。当我们执行shutdown.sh时,执行同样的代码,但是会传入shutdown的参数,同样读取server.xml配置,根据配置的端口,发送shutdown指令,这样启动的服务就收到了停机指令,就开始停机操作。通过启动和停机都读取同一份配置文件,避免启动和停机需要维护两份配置的问题。
鉴于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