복붙노트

[SPRING] 프로그래밍 방식으로 스프링 부트 응용 프로그램 다시 시작 / 스프링 컨텍스트 새로 고침

SPRING

프로그래밍 방식으로 스프링 부트 응용 프로그램 다시 시작 / 스프링 컨텍스트 새로 고침

사용자가 개입하지 않아도 Spring Application을 프로그래밍 방식으로 다시 시작하려고합니다.

기본적으로 응용 프로그램의 모드를 전환 할 수있는 페이지가 있습니다. 실제로는 현재 활성 프로필을 전환하는 것을 의미합니다. 그리고 문맥을 다시 시작해야한다는 것을 이해합니다.

현재 내 코드는 매우 간단합니다. 다시 시작하는 비트 용입니다 (이 방법은 Kotlin입니다).

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

그러나 context.close ()를 수행하는 순간 JVM이 즉시 존재합니다. 나는 또한 context.refresh ()를 시도했으나 Tomcat / Jetty (단순히 Tomcat 문제 일 때를 모두 시도)를 죽이는 것처럼 보였다. 그런 다음 아무 일도 일어나지 않는다.

나는 또한 프로그램 적으로 봄 부팅 응용 프로그램을 다시 시작한 것으로 보았지만 아무 것도 그 대답에서 나를 위해 작동하는 것 같습니다. 게다가 스프링 엑츄에이터를 살펴 보았습니다. 스프링 액추에이터는 / restart 끝 점이 있지만 더 이상 존재하지 않는 것 같습니까?

도움말 크게 감사하겠습니다. 감사.

해결법

  1. ==============================

    1.Alex의 솔루션이 효과가 있다고하더라도, 나는 하나의 작업을 수행 할 수 있도록 2 가지 추가 종속성 (액추에이터 및 클라우드 컨텍스트)을 포함하는 것을 믿지 않습니다. 대신, 나는 그의 대답을 결합하고 내 코드를 수정하여 내가 원하는 것을 해냈다.

    Alex의 솔루션이 효과가 있다고하더라도, 나는 하나의 작업을 수행 할 수 있도록 2 가지 추가 종속성 (액추에이터 및 클라우드 컨텍스트)을 포함하는 것을 믿지 않습니다. 대신, 나는 그의 대답을 결합하고 내 코드를 수정하여 내가 원하는 것을 해냈다.

    먼저, 새로운 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)
    }
    

    컨텍스트와 응용 프로그램이 응용 프로그램을 시작할 때 기본 방법에서 오는 경우 :

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

    이것이 문제를 일으키는 지 확실하지 않습니다. 있을 경우이 대답을 업데이트 할 것입니다. 희망적으로 이것은 다른 사람들에게 도움이 될 것입니다.

  2. ==============================

    2.누군가를 도울 수있는 경우 Crembo의 대답에 대한 Java 번역이 있습니다.

    누군가를 도울 수있는 경우 Crembo의 대답에 대한 Java 번역이 있습니다.

    컨트롤러 방법 :

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

    기본 클래스 (중요 비트 만) :

    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);
    
    }
    
  3. ==============================

    3.RestartEndPoint (스프링 - 클라우드 컨텍스트 종속성)를 사용하여 스프링 부트 응용 프로그램을 프로그래밍 방식으로 다시 시작할 수 있습니다.

    RestartEndPoint (스프링 - 클라우드 컨텍스트 종속성)를 사용하여 스프링 부트 응용 프로그램을 프로그래밍 방식으로 다시 시작할 수 있습니다.

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

    메모리 누수가 발생할 수 있음을 알리기 위해 예외가 발생하더라도 작동합니다.

    이 다른 질문에 대해서도 동일한 대답이 제공되었습니다 (다르게 다르게) : 자바 함수를 사용하여 스프링 부팅에서 호출 액츄에이터 / 재시작 엔드 포인트

  4. ==============================

    4.Spring Devtools의 Restarter를 사용하여이 문제를 해결했습니다. 이것을 pom.xml에 추가하십시오 :

    Spring Devtools의 Restarter를 사용하여이 문제를 해결했습니다. 이것을 pom.xml에 추가하십시오 :

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

    그런 다음 org.springframework.boot.devtools.restart.Restarter를 사용하십시오. 이것을 부르다 :

    Restarter.getInstance().restart();
    

    그것은 나를 위해 작동합니다. 희망이 도움이됩니다.

  5. from https://stackoverflow.com/questions/39386168/programatically-restart-spring-boot-application-refresh-spring-context by cc-by-sa and MIT license