我试图以编程方式重新启动Spring应用程序,而无需用户干预.

基本上,我有一个页面,允许切换应用程序的模式(实际上意味着切换当前活动的配置文件),据我所知,我必须重新启动上下文.

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立即就存在了.我也try 了context.refresh(),但这似乎简单地杀死了Tomcat/Jetty(两者都try 过,以防是Tomcat问题),然后什么也没有发生.

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的解决方案是works,但我不相信仅仅为了一个操作就包含两个额外的依赖项(ActuatorCloud Context).相反,我结合了他的答案,修改了我的代码,以便做我想做的事情.

首先,使用new Thread()setDaemon(false);执行代码是crucial.我有以下端点方法来处理重启:

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()

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)
}

其中contextapplication来自启动应用程序时的main方法:

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.

Kotlin相关问答推荐

如何创建继承抽象的匿名对象的新实例?

Lambda和普通Kotlin函数有什么区别?

我可以检测一个函数是否在Kotlin中被递归调用(即,重入)吗?

在Mapstruct中重用@映射定义

某些公共函数显然不能在类实例上访问;Klaxon示例

Kotlin:将泛型添加到列表任何>

KTOR';S函数`staticResources`在Kotlin本机目标上不可用

在Kotlin中的嵌套when语句中,else块是强制性的吗?

为什么 <= 可以应用于 Int 和 Long,而 == 不能?

Kotlin .如何用从 1 到 90 的 5 个唯一数字填充列表中的每一行?

如何连接两个 kotlin 流?

如何使用 Kotlin KClass 属性 simpleName 生成空值

如何使用 Findbugs 避免 kotlin 文件

Kotlin 中的部分类委托

如何解决此错误请Kotlin:[Internal Error] java.lang.ExceptionInInitializerError

如何通过反射使用 Kotlin 对象

Android 与 Kotlin - 如何使用 HttpUrlConnection

以Kotlin为单位的货币数据类型

如果作为 RxJava Observable 提供,Kotlin 密封类子类需要强制转换为基类

Android Studio - java.io.IOException:无法生成 v1 签名