作者:俞承豪那个男人- | 来源:互联网 | 2023-06-04 16:38
因业务需求,从内部停止并关闭springboot项目
首先说下遇到的需求,在项目中宁愿不执行也不能执行错误的需求时有发生,最近在做一个平台,在保存收款账户时考虑安全问题,在启动项目时作为必须校验项进行,如果校验不通过,阻止项目允许。
在百度上各种查,没有此类操作,现在研究出来了发现超级简单。写这篇文章的目的主要是记录下研究过程。心急的同学可以直接看的一部分,最终结果。
1、终于搞出来了
spring 的context(实现了ConfigurableApplicationContext的context)有一个close方法,在需要的地方执行context.close就好了。
2、我是怎么搞出来的
- 一、内事不决问百度(主要是Google不了啊~~)
刚开始我像往常一样,期待网友们有一个成熟的解决方案。但是,经过几个小时的查找和筛选,没有找到我想要的。也不是一无所获。网友们都很乐于奉献,只要搜springboot 启动,关闭,终止的,都能查到两种方法。
对于这个结果刚开始我是很不开森的,因为只有这个结果,而且能搜到的都是这个结果,达到了一遇到这个结果就关页面的程度,最后实在找不到解决方案了。我愤怒了,既然没有人有研究,我就来贡献时间。
既然spring官方提供了两种关闭服务的方法,说明可以做到,既然他们能做到,我也能!于是按照网友提供的步骤,下面引用网友提供的 通过http发送shutdown的方法 来研究
1.在pom.xml中引入actuator依赖
org.springframework.boot
spring-boot-starter-actuator
2.在application.properties文件开启shutdown endpoint,SpringBoot的endpoints.shutdown.enabled默认是关闭的。
#启用shutdown
endpoints.shutdown.enabled=true
#禁用密码验证
endpoints.shutdown.sensitive=false
经过简单的两步就能实现远程调用关闭系统,但这不是我想要的,我要找的是在系统里直接调用某个方法就能实现自动关闭。
要查找这个方法必须从官方提供的远程调用入手,远程调用使用的HTTP请求,于是要查找HTTP请求的服务接口,没办法只能打印日志慢慢找
找到这个入口后开始一步步debug,很痛苦的,因为你不知道哪一步系统就关闭了,只能在关闭系统的方法上加断点再次启动系统,执行关闭,如此反复查找了好几次,终于让我发现了关闭服务的老巢,哈哈哈哈!!!
老巢,spring-boot-actuator-1.5.4RELEASE.jar包里的ShutdownEndpoint这个类,下面贴出来主要代码,这段代码主要是说能关闭系统时,返回说正在关闭,启动关闭线程,调用this.context.close()。我去,终于让我知道了你的秘密,使用context就能关闭。好像我spring有获取context的方法吧,我去查查(本人技术水平有限,只是知道有这个事儿,这是后面故事的开始)。
ShutdownEndpoint的主要代码
public ShutdownEndpoint() {
super("shutdown", true, false);
}
@Override
public Map invoke() {
if (this.cOntext== null) {
return NO_CONTEXT_MESSAGE;
}
try {
return SHUTDOWN_MESSAGE;
}
finally {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500L);
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
ShutdownEndpoint.this.context.close();
}
});
thread.setContextClassLoader(getClass().getClassLoader());
thread.start();
}
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
if (context instanceof ConfigurableApplicationContext) {
this.cOntext= (ConfigurableApplicationContext) context;
}
}
spring有获取context的方法
中国网友就是给力,一搜一大把,都是一样的 —— 实现ApplicationContextAware接口
嗯,照着做,实现接口,东复制下,西复制下,怀着无比期待的心情执行测试……咦怎么没有关闭!!!!!
我去,debug,然后各种查,痛苦死了,下面给出错误代码(哪里错了自己看),希望网友们引以为戒
public class ShutdownContext implements ApplicationContextAware
{
private ConfigurableApplicationContext context;
public void showdown(){
if (null != context){
context.close();
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
if (context instanceof ConfigurableApplicationContext) {
this.cOntext= (ConfigurableApplicationContext) applicationContext;
}
}
}
————————————————美丽的分割线—————————————————————
有网友说使用我的代码运行不了,时隔好久也不记得哪里错了,对比了下代码才发现最后一个判断错误了,应该判断传入参数,判断了成员变量。下面是完整代码
import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix ="spring")
public class ShutdownContext implements ApplicationContextAware
{
private ConfigurableApplicationContext context;
public void showdown()
{
if (null != context)
{
context.close();
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
if (applicationContext instanceof ConfigurableApplicationContext) {
this.cOntext= (ConfigurableApplicationContext) applicationContext;
}
}
}