프로그래밍 방식으로 스프링 부트 응용 프로그램 다시 시작 / 스프링 컨텍스트 새로 고침
사용자가 개입하지 않고 프로그래밍 방식으로 Spring Application을 재시작하려고 합니다.
기본적으로 애플리케이션의 모드를 전환할 수 있는 페이지가 있으며(실제로는 현재 활성화된 프로파일을 전환하는 것을 의미합니다) 제가 이해하는 한 컨텍스트를 다시 시작해야 합니다.
현재 내 코드는 매우 간단합니다. 단지 재시작 비트를 위한 것입니다(그런데 이것은 Kotlin입니다).
context.close()
application.setEnvironment(context.environment)
ClassUtils.overrideThreadContextClassLoader(application.javaClass.classLoader)
context = application.run(*argsArray)
하지만 내가 하는 순간은context.close()
JVM이 즉시 존재합니다.저도 노력했습니다.context.refresh()
하지만 그것은 단순히 톰캣/제티를 죽이는 것처럼 보입니다. (톰캣 문제일 경우 둘 다 시도해 보았지만) 그리고 아무 일도 일어나지 않습니다.
또한 프로그래밍 방식으로 Spring Boot 애플리케이션을 재시작하는 것을 보았지만, 그 답변들을 보면 아무것도 효과가 없는 것 같습니다.또한 스프링 액츄에이터에 대해 조사했는데, 스프링 액츄에이터는 다음과 같습니다./restart
엔드포인트는 없어 보이는데요?
알렉스의 솔루션이 효과가 있지만, 2개의 추가 의존성을 포함하는 것을 믿지 않습니다 (Actuator
그리고.Cloud Context
한 번의 수술을 할 수 있게 된 것입니다.대신 그의 답변을 종합하고 내가 원하는 것을 하기 위해 코드를 수정했습니다.
따라서 우선, 코드를 실행하는 것이 중요합니다.new Thread()
그리고.setDaemon(false);
. 재시작을 처리하는 다음과 같은 Endpoint 메서드가 있습니다.
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)
}
어디에context
그리고.application
출신.main
응용 프로그램을 시작할 때 메소드:
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)
}
저는 이것이 문제를 일으키는지 완전히 확신할 수 없습니다.만약 있다면 이 답변을 업데이트하겠습니다.이것이 다른 사람들에게 조금이라도 도움이 되기를 바랍니다.
만약 누군가에게 도움이 될지도 모르니, 여기 크림보의 대답을 pura 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);
}
이미 언급했듯이, 스레드를 통한 재시작 구현은 한 번만 작동하고 두 번째는 컨텍스트가 null이기 때문에 NPE를 버립니다.
재시작 스레드가 초기 메인 호출 스레드와 동일한 클래스 로더를 사용하도록 함으로써 이 NPE를 방지할 수 있습니다.
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();
}
저는 스프링 데브툴즈의 리스타터를 사용하여 이 문제를 해결했습니다.pom.xml에 추가:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
그런 다음 org.springframework.boot.devtools.restart를 사용합니다.다시 시작하여 다음을 호출합니다.
Restarter.getInstance().restart();
저한테는 효과가 있어요.도움이 되길 바랍니다.
사용할 수 있습니다.RestartEndPoint
(에서)spring-cloud-context
종속성)을 사용하여 프로그래밍 방식으로 Spring Boot 응용 프로그램을 다시 시작합니다.
@Autowired
private RestartEndpoint restartEndpoint;
...
Thread restartThread = new Thread(() -> restartEndpoint.restart());
restartThread.setDaemon(false);
restartThread.start();
메모리 누수가 발생할 수 있음을 알려주는 예외가 발생하더라도 작동합니다.
[xyx] 웹 응용 프로그램이 [Thread-6]이라는 이름의 스레드를 시작했지만 중지하지 못했습니다.이로 인해 메모리 누수가 발생할 가능성이 매우 높습니다.스레드의 스택 추적:
이 다른 질문에 대해서도 동일한 답변이 제공되었습니다(다른 단어로 표시됨).자바 기능을 사용하여 스프링 부팅에서 스프링 액추에이터/재시동 엔드포인트 호출
아래의 재시작 방법이 작동합니다.
'@SpringBootApplication 공용 클래스 애플리케이션 {
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();
}
}`
언급URL : https://stackoverflow.com/questions/39386168/programmatically-restart-spring-boot-application-refresh-spring-context
'programing' 카테고리의 다른 글
jQuery에서 'data-sort' 속성에 따라 div를 정렬하시겠습니까? (0) | 2023.09.14 |
---|---|
JavaScript를 사용하여 XML 구문 분석 (0) | 2023.09.14 |
지정되지 않은 크기의 배열에 대한 포인터(*p)[]"C++에서는 불법이지만 C에서는 합법입니다. (0) | 2023.09.14 |
malloc()는 brk() 또는 mmap()을 사용합니까? (0) | 2023.09.14 |
문자열 변수에 추가 (0) | 2023.09.14 |