以编程方式重新启动 Spring Boot 应用程序/刷新 Spring 上下文

问题描述 投票:0回答:6

我正在尝试以编程方式重新启动我的 Spring 应用程序,而无需用户干预。

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

目前我的代码非常简单,只是为了重启(顺便说一句,这是 Kotlin):

    context.close()
    application.setEnvironment(context.environment)
    ClassUtils.overrideThreadContextClassLoader(application.javaClass.classLoader)
    context = application.run(*argsArray)

但是,当我这样做时,JVM 立即存在。我也尝试过

context.close()
但这似乎只是杀死了 Tomcat/Jetty(都尝试了以防万一是 Tomcat 问题),然后什么也没有发生。

我还看到了

以编程方式重新启动 Spring Boot 应用程序

,但从这些答案中似乎没有任何效果。此外,我研究了 Spring Actuator,据说它有 context.refresh() 端点,但它似乎不再存在了?

    

java spring spring-mvc spring-boot kotlin
6个回答
11
投票
有效

,但我不相信仅仅为了能够执行一项操作而包含 2 个额外的依赖项(/restart

Actuator
)。相反,我结合了他的答案并修改了我的代码,以便做我想做的事。

因此,首先,使用

Cloud Context

new Thread() 执行代码是

至关重要的
。我有以下处理重启的端点方法:

setDaemon(false);

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)

具有以下特点:


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

context
来自
application
方法:

main

我不完全确定这是否会产生任何问题。如果有的话,我会更新这个答案。希望这对其他人有帮助。


10
投票

控制器方法:

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

主类(仅有效位):

@GetMapping("/restart") void restart() { Thread restartThread = new Thread(() -> { try { Thread.sleep(1000); Main.restart(); } catch (InterruptedException ignored) { } }); restartThread.setDaemon(false); restartThread.start(); }

如果您启用了开发工具,它只会工作一次。第二次获得 NPE 


7
投票

可以通过让重新启动线程使用与初始主调用线程相同的类加载器来避免此 NPE:

private static String[] args; private static ConfigurableApplicationContext context; public static void main(String[] args) { Main.args = args; Main.context = SpringApplication.run(Main.class, args); } public static void restart() { // close previous context context.close(); // and build new one Main.context = SpringApplication.run(Main.class, args); }



6
投票

private static volatile ConfigurableApplicationContext context; private static ClassLoader mainThreadClassLoader; public static void main(String[] args) { mainThreadClassLoader = Thread.currentThread().getContextClassLoader(); 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.setContextClassLoader(mainThreadClassLoader); thread.setDaemon(false); thread.start(); }

然后使用org.springframework.boot.devtools.restart.Restarter
称之为:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency>

这对我有用。希望这有帮助。


3
投票
Restarter.getInstance().restart();

(在

RestartEndPoint
依赖项中)以编程方式重新启动 Spring Boot 应用程序:

spring-cloud-context

它可以工作,尽管它会抛出异常来通知您这可能会导致内存泄漏:

Web 应用程序 [xyx] 似乎启动了一个名为 [Thread-6] 但未能阻止它。这极有可能创造出一个 内存泄漏。线程的堆栈跟踪:

为另一个问题提供了相同的答案(措辞不同)

使用java函数从Spring boot调用Spring执行器/重新启动端点


0
投票

@Autowired private RestartEndpoint restartEndpoint; ... Thread restartThread = new Thread(() -> restartEndpoint.restart()); restartThread.setDaemon(false); restartThread.start();

如果您启用了开发工具,它只会工作一次。第二次获得 NPE 

© www.soinside.com 2019 - 2024. All rights reserved.