Programmatically restart Spring Application download / Update Spring Context

I am trying to programmatically restart a Spring application without user intervention.

Basically, I have a page that allows you to switch the application mode (actually means switching the current active profile), and as I understand it, I have to restart the context.

Currently, my code is very simple, it is just for restarting a bit (by the way, this is Kotlin):

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

However, the moment I do context.close() , the JVM exists immediately. I also tried context.refresh() , but it seems to just kill Tomcat / Jetty (tried both in case this was a Tomcat problem) and then nothing happens.

I also saw programmatically restarting the Spring application to load , but nothing works for me from these answers. Also, I looked at the Spring Actuator, which supposedly has a /restart endpoint, but it looks like it no longer exists?

Help would be greatly appreciated. Thanks.

+9
source share
5 answers

Although Alex’s solution works, I don’t believe in including two additional dependencies ( Actuator and Cloud Context ) in order to be able to perform one operation. Instead, I combined his answer and changed my code to do what I wanted.

So, first of all, it is important that the code is executed using new Thread() and setDaemon(false); . I have the following endpoint method that handles a 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) not required, but I want my controller to display a view before actually restarting the application.

SpringMain.restartToMode has the following:

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

Where context and application come from the main method when 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'm not quite sure if this is creating problems. If so, I will update this answer. Hope this helps any other.

+10
source

In case this can help someone, here is Carmbo's accepted answer for Java.

Controller Method:

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

Main class (only for significant bits):

 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
source

You can use RestartEndPoint (in the spring-cloud-context dependency) to restart the Spring boot application programmatically:

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

It works, although it will throw an exception to tell you that this could lead to memory leaks:

The web application [xyx] seems to have started a thread named [Thread-6], but could not stop it. This is likely to create a memory leak. Trace flow stream:

The same answer was provided for this other question (in different ways) : Call Spring endpoint executive / restart with Spring using java function

+3
source

I solved this problem using Restarter from Spring Devtools. Add this to pom.xml:

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

Then use org.springframework.boot.devtools.restart.Restarter to call this:

 Restarter.getInstance().restart(); 

It works for me. Hope this helps.

0
source

Below restart method will work.

'@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(); } 

} "

0
source

All Articles