问题描述
我试图以编程方式重新启动我的Spring应用程序,而无需用户干预。
I am trying to programatically restart my Spring Application without having the user to intervene.
基本上,我有一个允许切换应用程序模式的页面(实际上意味着切换当前活动的配置文件)并且据我所知,我必须重新启动上下文。
Basically, I have a page which allows to switch the mode of the application (actually meaning switching the currently active profile) and as far as I understand I must restart the context.
目前我的代码非常简单,它仅用于重启位(这个顺便说一句是Kotlin):
Currently my code is very simple, it's just for the restarting bit (this is Kotlin by the way):
context.close()
application.setEnvironment(context.environment)
ClassUtils.overrideThreadContextClassLoader(application.javaClass.classLoader)
context = application.run(*argsArray)
但是,当我做 context.close()
时,JVM立即存在。我也尝试了 context.refresh()
但这似乎只是杀死了Tomcat / Jetty(只是在遇到Tomcat问题的情况下尝试了)然后没有任何反应。
However the moment I do context.close()
the JVM exists immediately. I have also tried context.refresh()
but that seems to simply kill Tomcat/Jetty (tried both just in case it was a Tomcat problem) and then nothing happens.
我还看过但这些答案对我来说似乎没什么用处。此外,我查看了Spring Actuator,它应该有 / restart
端点,但那似乎不再存在了?
I have also seen Programmatically restart Spring Boot application but nothing seems to work for me from those answers. Furthermore, I looked into Spring Actuator which supposedly has the /restart
endpoint, but that doesn't seem to be there anymore?
非常感谢帮助。谢谢。
推荐答案
即使Alex的解决方案有效,我也不相信包含2个额外的依赖项( Actuator
和 Cloud Context
)只是为了能够进行一项操作。相反,我已经结合他的答案并修改了我的代码,以便做我想做的事。
Even though Alex's solution works, I don't believe in including 2 additional dependencies (Actuator
and Cloud Context
) just to be able to do one operation. Instead, I have combined his answer and modified my code in order to do what I wanted.
所以,首先,它是至关重要代码是使用 new Thread()
和 setDaemon(false);
执行的。我有以下处理重启的端点方法:
So, first of all, it is crucial that the code is executed using new Thread()
and setDaemon(false);
. I have the following endpoint method that handles the restart:
val restartThread = Thread {
logger.info("Restarting...")
Thread.sleep(1000)
SpringMain.restartToMode(AppMode.valueOf(change.newMode.toUpperCase()))
logger.info("Restarting... Done.")
}
restartThread.isDaemon = false
restartThread.start()
不需要 Thread.sleep(1000)
,但我希望我的控制器在实际重启应用程序之前输出视图。
The Thread.sleep(1000)
is not required, but I want my controller to output the view before actually restarting the application.
SpringMain.restartToMode
具有以下内容:
@Synchronized fun restartToMode(mode: AppMode) {
requireNotNull(context)
requireNotNull(application)
// internal logic to potentially produce a new arguments array
// close previous context
context.close()
// and build new one using the new mode
val builder = SpringApplicationBuilder(SpringMain::class.java)
application = builder.application()
context = builder.build().run(*argsArray)
}
其中上下文
和应用程序
在启动应用程序时来自 main
方法:
Where context
and application
come from the main
method upon starting the application:
val args = ArrayList<String>()
lateinit var context: ConfigurableApplicationContext
lateinit var application: SpringApplication
@Throws(Exception::class)
@JvmStatic fun main(args: Array<String>) {
this.args += args
val builder = SpringApplicationBuilder(SpringMain::class.java)
application = builder.application()
context = builder.build().run(*args)
}
我不完全确定这是否会产生任何问题。如果有,我会更新这个答案。希望这对其他人有任何帮助。
I am not entirely sure if this produces any problems. If there will be, I will update this answer. Hopefully this will be of any help to others.
这篇关于以编程方式重新启动Spring Boot应用程序/刷新Spring Context的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!