I am trying to programmatically 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.
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)
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.
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?
You can use: POST to /actuator/env to update the Environment and rebind @ConfigurationProperties and log levels. /actuator/refresh to re-load the boot strap context and refresh the @RefreshScope beans. /actuator/restart to close the ApplicationContext and restart it (disabled by default).
The very basic way to restart the Spring Boot Application is by sending a POST request to the /restart endpoint.
In Spring Boot this can be achieved by adding a DevTools module, just add the following dependency in your Spring Boots pom. xml and build it. Spring Boot DevTools module does exactly what developers needed, this eliminates the process of manually deploying the changes.
I've solved this issue by 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 help.
As was commented already, the restart-via-thread implementations given before only work once, and second time around throw a NPE because context is null.
This NPE can be avoided by having the restart thread use the same class loader as the initial main-invoking thread:
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With