2016-09-08 3 views
4

Ich versuche, meine Spring Application programmatisch neu zu starten, ohne dass der Benutzer eingreifen muss.Neustart der Spring Boot-Anwendung/Refresh Spring Context

Grundsätzlich habe ich eine Seite, die es erlaubt, den Modus der Anwendung zu wechseln (eigentlich bedeutet das Umschalten des gerade aktiven Profils) und soweit ich weiß muss ich den Kontext neu starten.

Derzeit mein Code ist sehr einfach, es ist nur für das Neustarten Bit (dies ist Kotlin by the way):

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

jedoch der Moment, als ich context.close() tun die JVM sofort vorhanden ist. Ich habe auch versucht context.refresh(), aber das scheint Tomcat/Jetty einfach zu töten (versuchte beide nur für den Fall, dass es ein Tomcat-Problem war) und dann passiert nichts.

Ich habe auch gesehen Programmatically restart Spring Boot application aber nichts scheint für mich aus diesen Antworten zu arbeiten. Außerdem habe ich mir Spring Actuator angeschaut, der angeblich den /restart Endpunkt hat, aber das scheint nicht mehr da zu sein?

Hilfe wäre sehr willkommen. Vielen Dank.

+0

Ich habe gerade gelesen, etwas über Federwolke letzte Mal, und es wurde endpoint' ein 'aufzufrischen, die al erfrischt die Bohnen im Kontext. Vielleicht findest du dort etwas hilfreiches. [Refresh Scope] (http://projects.spring.io/spring-cloud/spring-cloud.html) – Patrick

+0

Warum ist das mit "java" markiert? –

+0

Weil es mir egal war, wenn jemand eine Lösung in Java oder Kotlin hatte. Kotlin hat in dieser Frage keine Bedeutung. – Crembo

Antwort

4

Auch wenn Alex Lösung funktioniert, ich glaube nicht an, darunter 2 zusätzliche Abhängigkeiten (Actuator und Cloud Context) nur um eine Operation zu machen. Stattdessen habe ich seine Antwort kombiniert und meinen Code geändert, um zu tun, was ich wollte.

Also, zunächst einmal ist es von entscheidender Bedeutung , dass der Code ausgeführt wird new Thread() und setDaemon(false); verwenden. Ich habe folgende Endpunkt-Methode, die den Neustart Griffe:

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

Die Thread.sleep(1000) nicht erforderlich ist, aber ich möchte, dass meine Controller zur Ausgabe der Ansicht, bevor die Anwendung tatsächlich neu zu starten.

SpringMain.restartToMode hat folgende:

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

Wo context und application aus dem main Verfahren kommen beim Starten der Anwendung:

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

Ich bin nicht ganz sicher, ob dies irgendwelche Probleme erzeugt. Wenn es wird, werde ich diese Antwort aktualisieren. Hoffentlich wird dies anderen helfen.

3

Sie können die RestartEndPoint (in spring-cloud-context Abhängigkeit) der Frühling Boot-Anwendung programmatisch neu zu starten:

@Autowired 
private RestartEndpoint restartEndpoint; 

... 

Thread restartThread = new Thread(() -> restartEndpoint.restart()); 
restartThread.setDaemon(false); 
restartThread.start(); 

Es funktioniert, auch wenn es eine Ausnahme auslösen, werden Sie darüber informieren, dass dies zu Speicherlecks führen können:

Die Web-Anwendung [xyx] erscheint ein Gewinde namens [Faden 6] begonnen zu haben, aber um es zu stoppen, ist fehlgeschlagen. Dies führt sehr wahrscheinlich zu einem Speicherverlust von . Stack-Trace thread:

Die gleiche Antwort für diese andere Frage zur Verfügung gestellt wurde (anders formuliert): Call Spring actuator /restart endpoint from Spring boot using a java function

+1

Auch wenn Ihre Antwort nicht genau das war, was ich brauchte, habe ich Ihre Antwort verwendet, um eine Lösung zu finden, die für mich funktioniert. Siehe meine selbst gepostete Antwort. Vielen Dank. – Crembo

1

Falls es jemandem helfen könnte, hier ist eine Pura-Java-Übersetzung von Crembo's akzeptierter Antwort.

Controller-Methode:

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

Hauptklasse (Bits nur):

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

} 
Verwandte Themen