The role and difference between SmartLifecycle and Lifecycle in Spring

This article is based on SpringBoot 2.5.0-M2explaining the role and difference of Spring neutralization Lifecycleand SmartLifecyclehow to control the priority of SmartLifecycle.
And explain how SmartLifecycleto start/stop the web container in SpringBoot .

SmartLifecycle & Lifecycle functions and differences

The role of SmartLifecycle and Lifecycle

  1. 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

  1. SmartLifecycleThe interface inherits the Lifecycleinterface, and at the same time inherits the org.springframework.context.Phasedinterface to control SmartLifecyclethe priority between multiple implementations.
  2. In the SpringBoot application, or in the Spring application does not call the AbstractApplicationContext#startmethod, if a Bean only implements the Lifecycleinterface:
    • Not execute Lifecycleinterface startup method , including the Lifecycle#isRunningmethod it will not be executed.
    • However, in the application when you exit will execute Lifecycle#isRunninga method to determine the Lifecyclewhether has been started, if it returns true then calling Lifecycle#stop()the shutdown method .
  3. If a Bean implements the SmartLifecycleinterface, the startup method will be executed . First, it will be Phasedgrouped according to the interface priority, encapsulated LifecycleGroup, and then the LifecycleGroup#start()method will be called in a loop to SmartLifecycle#isRunningdetermine whether it has been executed. If it returns false to indicate that it has not been executed, the execution will be called SmartLifecycle#start(). PhasedThe smaller the return value, the higher the priority.
  4. SmartLifecycleThere is also a isAutoStartupmethod in it, if it returns false, the start method will not be executed at startup, and it will return by defaulttrue

Source code analysis

SmartLifecycleLifecycleBoth and are org.springframework.context.support.DefaultLifecycleProcessorcalled in, the
DefaultLifecycleProcessor#onRefreshmethod AbstractApplicationContext#finishRefreshwill 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#onRefreshSource code:

@Override
public void onRefresh() {
    
    
	startBeans(true);  //autoStartupOnly = true
	this.running = true;
}

DefaultLifecycleProcessor#startBeansThe source code is as follows:
autoStartupOnlyWhen onRefresh is passed true, it means that only beans that can be started automatically are executed, that is, SmartLifecyclethe implementation class of :, and the SmartLifecycle#isAutoStartupreturn 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#doCloseexit, whether it is SmartLifecycleor Lifecyclewill be executed isRunningmethod, has been launched to determine whether to return true if already started, is executed SmartLifecycleor Lifecyclethe stopmethod.
See the source code: org.springframework.context.support.DefaultLifecycleProcessor#doStopmethod.

The execution is AbstractApplicationContext#doClosegenerally the exit of the application process, through the hook method registered by the jvm, or the application code call.
AbstractApplicationContext#registerShutdownHookSource 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 LifecycleProcessorinterface. 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.LifecycleAutoConfigurationSource 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 SmartLifecycleembedded web container is started through implementation , and the implementation class is as follows WebServerStartStopLifecycle.

ServletWebServerApplicationContextonRefreshCalled createWebServerin a createWebServermethod, an org.springframework.boot.web.server.WebServerinstance 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#createWebServerSource 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();
}

createWebServerThe method will webServerencapsulate the created WebServerStartStopLifecycleobject in the object and register it in the Spring container.

org.springframework.boot.web.servlet.context.WebServerStartStopLifecycleThe 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;  }
}

WebServerStartStopLifecycleThe SmartLifecycleinterface is implemented . When Spring SmartLifecyclecalls 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 applicationContextpublished to ServletWebServerInitializedEventindicate that the web container has started successfully and can receive http requests.

And SmartInitializingSingletondifference

The same point:SmartInitializingSingleton and Lifecycle, SmartLifecycleare executed after all single-instance beans are created (getBean method).

difference:

  1. SmartInitializingSingletonTake precedence over Lifecycleand SmartLifecycleexecute.
  2. SmartInitializingSingletonThere is only one afterSingletonsInstantiatedway. And Lifecyclethere are start,, stopand isRunningother methods.
  3. SmartInitializingSingletonThe order of execution cannot be sequenced between multiple implementations, but SmartLifecyclethe Phasedinterface is implemented , and the sequence of execution can be int getPhase()controlled.
  4. SmartInitializingSingletonThe @DependsOnorder of execution can be controlled by between , but this is achieved by the function and principle of the @DependsOn annotation in Spring . It is not SmartInitializingSingletona sort.

Guess you like

Origin blog.csdn.net/u013202238/article/details/114489001