This article is based on SpringBoot 2.5.0-M2
explaining the role and difference of Spring neutralization Lifecycle
and SmartLifecycle
how to control the priority of SmartLifecycle.
And explain how SmartLifecycle
to start/stop the web container in SpringBoot .
SmartLifecycle & Lifecycle functions and differences
The role of SmartLifecycle and Lifecycle
- They all allow developers to perform their own initialization work after all beans are created (getBean) , or perform resource destruction work when exiting .
The difference between SmartLifecycle and Lifecycle
SmartLifecycle
The interface inherits theLifecycle
interface, and at the same time inherits theorg.springframework.context.Phased
interface to controlSmartLifecycle
the priority between multiple implementations.- In the SpringBoot application, or in the Spring application does not call the
AbstractApplicationContext#start
method, if a Bean only implements theLifecycle
interface:- Not execute
Lifecycle
interface startup method , including theLifecycle#isRunning
method it will not be executed. - However, in the application when you exit will execute
Lifecycle#isRunning
a method to determine theLifecycle
whether has been started, if it returns true then callingLifecycle#stop()
the shutdown method .
- Not execute
- If a Bean implements the
SmartLifecycle
interface, the startup method will be executed . First, it will bePhased
grouped according to the interface priority, encapsulatedLifecycleGroup
, and then theLifecycleGroup#start()
method will be called in a loop toSmartLifecycle#isRunning
determine whether it has been executed. If it returns false to indicate that it has not been executed, the execution will be calledSmartLifecycle#start()
.Phased
The smaller the return value, the higher the priority. SmartLifecycle
There is also aisAutoStartup
method in it, if it returnsfalse
, the start method will not be executed at startup, and it will return by defaulttrue
Source code analysis
SmartLifecycle
Lifecycle
Both and are org.springframework.context.support.DefaultLifecycleProcessor
called in, the
DefaultLifecycleProcessor#onRefresh
method AbstractApplicationContext#finishRefresh
will be called during execution , the call stack is as follows:
startBeans:142, DefaultLifecycleProcessor (org.springframework.context.support)
onRefresh:123, DefaultLifecycleProcessor (org.springframework.context.support)
finishRefresh:934, AbstractApplicationContext (org.springframework.context.support)
refresh:585, AbstractApplicationContext (org.springframework.context.support)
refresh:144, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:755, SpringApplication (org.springframework.boot)
refreshContext:426, SpringApplication (org.springframework.boot)
run:326, SpringApplication (org.springframework.boot)
run:1299, SpringApplication (org.springframework.boot)
run:1288, SpringApplication (org.springframework.boot)
main:31, DemoApplication (com.example.demo)
DefaultLifecycleProcessor#onRefresh
Source code:
@Override
public void onRefresh() {
startBeans(true); //autoStartupOnly = true
this.running = true;
}
DefaultLifecycleProcessor#startBeans
The source code is as follows:
autoStartupOnly
When onRefresh is passed true, it means that only beans that can be started automatically are executed, that is, SmartLifecycle
the implementation class of :, and the SmartLifecycle#isAutoStartup
return value must be true.
private void startBeans(boolean autoStartupOnly) {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new TreeMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(bean);
phases.computeIfAbsent(phase, p ->
new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly)
).add(beanName, bean);
}
});
if (!phases.isEmpty()) {
phases.values().forEach(LifecycleGroup::start);
}
}
The Spring AbstractApplicationContext#doClose
exit, whether it is SmartLifecycle
or Lifecycle
will be executed isRunning
method, has been launched to determine whether to return true if already started, is executed SmartLifecycle
or Lifecycle
the stop
method.
See the source code: org.springframework.context.support.DefaultLifecycleProcessor#doStop
method.
The execution is AbstractApplicationContext#doClose
generally the exit of the application process, through the hook method registered by the jvm, or the application code call.
AbstractApplicationContext#registerShutdownHook
Source code
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
@Override
public void run() {
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
Customize LifecycleProcessor to process Lifecycle
Mentioned in the source code analysis DefaultLifecycleProcessor
, it implements the LifecycleProcessor
interface. However, we can also implement this interface ourselves, replacing the default one DefaultLifecycleProcessor
. In SpringBoot, it is configured by itself DefaultLifecycleProcessor
, and we can override the default implementation in the same way. For example Lifecycle
, the start()
method in can be executed during onRefresh().
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration
Source code:
/**
* {@link EnableAutoConfiguration Auto-configuration} relating to the application
* context's lifecycle.
*
* @author Andy Wilkinson
* @since 2.3.0
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(LifecycleProperties.class)
public class LifecycleAutoConfiguration {
@Bean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME)
@ConditionalOnMissingBean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME,
search = SearchStrategy.CURRENT)
public DefaultLifecycleProcessor defaultLifecycleProcessor(LifecycleProperties properties) {
DefaultLifecycleProcessor lifecycleProcessor = new DefaultLifecycleProcessor();
lifecycleProcessor.setTimeoutPerShutdownPhase(properties.getTimeoutPerShutdownPhase().toMillis());
return lifecycleProcessor;
}
}
Start time of embedded web container in SpringBoot
In SpringBoo, the SmartLifecycle
embedded web container is started through implementation , and the implementation class is as follows WebServerStartStopLifecycle
.
ServletWebServerApplicationContext
onRefresh
Called createWebServer
in a createWebServer
method, an org.springframework.boot.web.server.WebServer
instance is created in the method, and the object contains methods to control the start and stop of the web container ( tomcat
, jetty
).
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
ServletWebServerApplicationContext#createWebServer
Source code:
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
ServletWebServerFactory factory = getWebServerFactory();
createWebServer.tag("factory", factory.getClass().toString());
this.webServer = factory.getWebServer(getSelfInitializer());
createWebServer.end();
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
createWebServer
The method will webServer
encapsulate the created WebServerStartStopLifecycle
object in the object and register it in the Spring container.
org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle
The source code is as follows:
class WebServerStartStopLifecycle implements SmartLifecycle {
private final ServletWebServerApplicationContext applicationContext;
private final WebServer webServer;
private volatile boolean running;
WebServerStartStopLifecycle(ServletWebServerApplicationContext applicationContext, WebServer webServer) {
this.applicationContext = applicationContext;
this.webServer = webServer;
}
@Override
public void start() {
this.webServer.start();
this.running = true;
this.applicationContext
.publishEvent(new ServletWebServerInitializedEvent(this.webServer, this.applicationContext));
}
@Override
public void stop() {
this.webServer.stop(); }
@Override
public boolean isRunning() {
return this.running; }
@Override
public int getPhase() {
return Integer.MAX_VALUE - 1; }
}
WebServerStartStopLifecycle
The SmartLifecycle
interface is implemented . When Spring SmartLifecycle
calls back to the interface method, the this.webServer.start();
web container is called to start. After the web container is started , an event will be applicationContext
published to ServletWebServerInitializedEvent
indicate that the web container has started successfully and can receive http requests.
And SmartInitializingSingleton
difference
The same point:SmartInitializingSingleton
and Lifecycle
, SmartLifecycle
are executed after all single-instance beans are created (getBean method).
difference:
SmartInitializingSingleton
Take precedence overLifecycle
andSmartLifecycle
execute.SmartInitializingSingleton
There is only oneafterSingletonsInstantiated
way. AndLifecycle
there arestart
,,stop
andisRunning
other methods.SmartInitializingSingleton
The order of execution cannot be sequenced between multiple implementations, butSmartLifecycle
thePhased
interface is implemented , and the sequence of execution can beint getPhase()
controlled.SmartInitializingSingleton
The@DependsOn
order of execution can be controlled by between , but this is achieved by the function and principle of the @DependsOn annotation in Spring . It is notSmartInitializingSingleton
a sort.