Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically restart Spring Boot application / Refresh Spring Context

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?

like image 712
Crembo Avatar asked Sep 08 '16 08:09

Crembo


People also ask

How do I refresh application context in spring boot?

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

How do I restart my spring boot app?

The very basic way to restart the Spring Boot Application is by sending a POST request to the /restart endpoint.

How do I reload my changes on spring boot without having to restart server?

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.


2 Answers

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.

like image 107
Lucifer Nick Avatar answered Oct 04 '22 20:10

Lucifer Nick


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();
}
like image 33
johnwoo Avatar answered Oct 04 '22 18:10

johnwoo