mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-23 14:40:00 +00:00
Introduce ConfigurableApplicationContext.restart() method
Closes gh-35171
This commit is contained in:
+11
@@ -220,6 +220,17 @@ public interface ConfigurableApplicationContext extends ApplicationContext, Life
|
||||
*/
|
||||
void refresh() throws BeansException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Stop all beans in this application context if necessary, and subsequently
|
||||
* restart all auto-startup beans, effectively restoring the lifecycle state
|
||||
* after {@link #refresh()} (typically after a preceding {@link #stop()} call
|
||||
* when a full {@link #start()} of even lazy-starting beans is to be avoided).
|
||||
* @since 7.0
|
||||
* @see #stop()
|
||||
* @see SmartLifecycle#isAutoStartup()
|
||||
*/
|
||||
void restart();
|
||||
|
||||
/**
|
||||
* Register a shutdown hook with the JVM runtime, closing this context
|
||||
* on JVM shutdown unless it has already been closed at that time.
|
||||
|
||||
@@ -26,13 +26,31 @@ package org.springframework.context;
|
||||
public interface LifecycleProcessor extends Lifecycle {
|
||||
|
||||
/**
|
||||
* Notification of context refresh, for example, for auto-starting components.
|
||||
* Notification of context refresh for auto-starting components.
|
||||
* @see ConfigurableApplicationContext#refresh()
|
||||
*/
|
||||
void onRefresh();
|
||||
default void onRefresh() {
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification of context close phase, for example, for auto-stopping components.
|
||||
* Notification of context restart for auto-stopping and subsequently
|
||||
* auto-starting components.
|
||||
* @since 7.0
|
||||
* @see ConfigurableApplicationContext#restart()
|
||||
*/
|
||||
void onClose();
|
||||
default void onRestart() {
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification of context close phase for auto-stopping components
|
||||
* before destruction.
|
||||
* @see ConfigurableApplicationContext#close()
|
||||
*/
|
||||
default void onClose() {
|
||||
stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -1548,6 +1548,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
publishEvent(new ContextStoppedEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restart() {
|
||||
getLifecycleProcessor().onRestart();
|
||||
publishEvent(new ContextStartedEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return (this.lifecycleProcessor != null && this.lifecycleProcessor.isRunning());
|
||||
|
||||
+10
@@ -314,6 +314,16 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestart() {
|
||||
this.stoppedBeans = null;
|
||||
if (this.running) {
|
||||
stopBeans();
|
||||
}
|
||||
startBeans(true);
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
stopBeans();
|
||||
|
||||
+50
-11
@@ -348,6 +348,40 @@ class DefaultLifecycleProcessorTests {
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void contextRefreshThenRestartWithMixedBeans() {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<>();
|
||||
TestSmartLifecycleBean smartBean1 = TestSmartLifecycleBean.forShutdownTests(5, 0, stoppedBeans);
|
||||
TestSmartLifecycleBean smartBean2 = TestSmartLifecycleBean.forShutdownTests(-3, 0, stoppedBeans);
|
||||
smartBean2.setAutoStartup(false);
|
||||
context.getBeanFactory().registerSingleton("smartBean1", smartBean1);
|
||||
context.getBeanFactory().registerSingleton("smartBean2", smartBean2);
|
||||
|
||||
assertThat(smartBean1.isRunning()).isFalse();
|
||||
assertThat(smartBean2.isRunning()).isFalse();
|
||||
context.refresh();
|
||||
assertThat(smartBean1.isRunning()).isTrue();
|
||||
assertThat(smartBean2.isRunning()).isFalse();
|
||||
context.restart();
|
||||
assertThat(stoppedBeans).containsExactly(smartBean1);
|
||||
assertThat(smartBean1.isRunning()).isTrue();
|
||||
assertThat(smartBean2.isRunning()).isFalse();
|
||||
smartBean1.stop();
|
||||
assertThat(stoppedBeans).containsExactly(smartBean1, smartBean1);
|
||||
assertThat(smartBean1.isRunning()).isFalse();
|
||||
assertThat(smartBean2.isRunning()).isFalse();
|
||||
context.restart();
|
||||
assertThat(stoppedBeans).containsExactly(smartBean1, smartBean1);
|
||||
assertThat(smartBean1.isRunning()).isTrue();
|
||||
assertThat(smartBean2.isRunning()).isFalse();
|
||||
context.start();
|
||||
assertThat(smartBean1.isRunning()).isTrue();
|
||||
assertThat(smartBean2.isRunning()).isTrue();
|
||||
context.close();
|
||||
assertThat(stoppedBeans).containsExactly(smartBean1, smartBean1, smartBean1, smartBean2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledForTestGroups(LONG_RUNNING)
|
||||
void smartLifecycleGroupShutdown() {
|
||||
@@ -741,17 +775,22 @@ class DefaultLifecycleProcessorTests {
|
||||
// invocation order in the 'stoppedBeans' list
|
||||
stop();
|
||||
final int delay = this.shutdownDelay;
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
finally {
|
||||
callback.run();
|
||||
}
|
||||
}).start();
|
||||
if (delay > 0) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
finally {
|
||||
callback.run();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user