# 1.场景
在测试项目或者生产项目中,由于修改了一些配置参数文件或者必须需要重启,我们此时可以不需要通过运维打包发布,可以实现快速优雅的重启。
就如同Halo项目一样,在线修改application.yml文件后,可以在线重启。如下图

# 2.原理
核心类为:**ConfigurableApplicationContext**,它是SpringApplication.run(Application.class,args)运行的返回对象
1. 主程序启动时,通过**static ConfigurableApplicationContext**常量保存SpringApplication.run(Application.class,args)的返回值
2. 从ConfigurableApplicationContext获取Bean(ApplicationArguments)对象
3. 启动一个非Damon线程
4. 调用ConfigurableApplicationContext.close()方法,关闭当前应用的上下文
5. 重新运行SpringApplication.run(Application.class,args)方法,并将返回值赋值给**static ConfigurableApplicationContext**
6. 重启成功
# 3.code
## 3.1 main方法
```java
@SpringBootApplication
public class Application{
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(Application.class, args);
}
public static void restart() {
ApplicationArguments args = context.getBean(ApplicationArguments.class);
Thread thread = new Thread(() -> {
context.close();
context = SpringApplication.run(Application.class, args.getSourceArgs());
});
thread.setDaemon(false);
thread.start();
}
}
```
## 3.2 controller方法
```java
@RestController
public class RestartController {
@Value("${spring.application.name}")
String name;
private static Logger logger = LoggerFactory.getLogger(RestartController.class);
@RequestMapping("/info")
public String info() {
logger.info("spring.application.name:" + name);
return name;
}
@RequestMapping("/restart")
public void restart() {
//此处修改spring.application.name只为验证是否重启成功,实际可去除
try {
PropUtil instance = PropUtil.getProp("application.properties");
instance.setProperty("spring.application.name", "Fredia.wang");
} catch (Exception e) {
e.printStackTrace ( );
}
//重启
Application.restart();
}
}
```
## 3.3 propertis工具
```java
/**
* properties 工具
*/
public class PropUtil {
private static PropertiesConfiguration propConfig = null;
private static final PropUtil PROP_UTIL = new PropUtil();
private PropUtil() {
}
public static PropUtil getProp(String propertiesFile) {
//执行初始化
init(propertiesFile);
return PROP_UTIL;
}
private static void init(String propertiesFile) {
try {
propConfig = new PropertiesConfiguration(propertiesFile);
//自动重新加载
propConfig.setReloadingStrategy(new FileChangedReloadingStrategy());
//自动保存
propConfig.setAutoSave(true);
propConfig.save();
} catch (Exception e) {
e.printStackTrace();
}
}
public Object getValue(String key) {
return propConfig.getProperty(key);
}
public void setProperty(String key, String value) {
propConfig.setProperty(key, value);
}
}
```
## 3.4 验证步骤
1. 启动项目后,先访问项目/info,确认当前项目名称
2. 访问/restart接口,控制台验证
3. 再次访问/info,确认项目名称是否变更
验证图如下



# 4.总结
理论上,生产项目是不能如此用这个方法的。测试环境或者预生产环境,在紧急情况下,尤其是在k8s体系下想节省编译打tag的情况下,可以适度使用。既然是spring官方提供的方法,肯定有其用武之地。项目的配置和管理都在向可视化,简单化发展。核心技术在逐渐下沉的时代,技术人员其实应该对自我的要求更高了。“只知其然,而不知其所以然”是一件恐怖的事。

如何在线重启 SpringBoot 应用程序