Introduce ConfigurableApplicationContext.restart() method
Closes gh-35171
This commit is contained in:
parent
b48da4c0c2
commit
523552ac2e
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue