The main content of this article: take you to master the life cycle of spring application context.
Why do you need to master this?
1. In response to the interview, I often ask
2. If you want to extend spring in the project, you must master this part
3. Easier to read spirng source code
1. What is the spring application context?
The interface org.springframework.context.ApplicationContext represents the spring context. The following two implementation classes
org.springframework.context.support.ClassPathXmlApplicationContext
org.springframework.context.annotation.AnnotationConfigApplicationContext
2. Application life cycle (14 phases)
1. Create spring application context
2. Context start preparation phase
3. BeanFactory creation phase
4. BeanFactory preparation phase
5. BeanFactory post processing phase
6. BeanFactory registers the BeanPostProcessor phase
7. Initialize built-in Bean: MessageSource
8. Initialize the built-in Bean: Spring event broadcaster
9. Spring application context refresh phase
10. Spring event listener registration phase
11. Singleton bean instantiation phase
12. BeanFactory initialization completion phase
13. Spring application context startup completion phase
14. Spring application context closing phase
3. Use of Spring application context
Take a look at this code. Are you familiar with it? This is the most common usage of spring context. Later, we will take this code as an example and elaborate on the details of each stage in combination with the spring source code.
@Configuration @ComponentScan public class MainConfig { public static void main(String[] args) { //1.establish spring context AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(); //2.Register in context bean configApplicationContext.register(MainConfig.class); //3.Refresh spring Context, internal startup spring context configApplicationContext.refresh(); //4.close spring context System.out.println("stop ok!"); } }
4. Phase 1: create Spring application context
Corresponding to this code
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext();
Take a look at its class diagram, which mainly lists the 2 parent classes of annotationconfigapplicationcontext
When calling the constructor of a subclass, the constructor of the parent class will be called automatically by default. First, take a look at the source code of the GenericApplicationContext constructor, as shown below, and create the beanFactory.
public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
Let's take a look at the source code of the AnnotationConfigApplicationContext constructor, as follows:
public AnnotationConfigApplicationContext() { //establish AnnotatedBeanDefinitionReader: Used to read and register data defined by annotation bean this.reader = new AnnotatedBeanDefinitionReader(this); //@1 //establish ClassPathBeanDefinitionScanner: bean Define a scanner to scan the classes in the package. For the classes that meet the conditions, they will be registered to spring In container this.scanner = new ClassPathBeanDefinitionScanner(this); }
@1: new AnnotatedBeanDefinitionReader(this), enter this method, and finally go to the following method. A very key method will register five key beans with the spring container. These beans are very important.
org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { //1,register ConfigurationClassPostProcessor,This is a very critical class that implements BeanDefinitionRegistryPostProcessor Interface // ConfigurationClassPostProcessor The main thing this class does: be responsible for all bean Registration of,If you want to see bean To register the source code, you can postProcessBeanDefinitionRegistry Method if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } //2,register AutowiredAnnotationBeanPostProcessor: Responsible for handling@Autowire annotation if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } //3,register CommonAnnotationBeanPostProcessor: Responsible for handling@Resource annotation if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } //4,register EventListenerMethodProcessor: Responsible for handling@EventListener Annotation method, i.e. event handler if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME)); } //5,register DefaultEventListenerFactory: Be responsible for@EventListener The marking method is packaging ApplicationListener object if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); } return beanDefs; }
Let's take a look at the above code, which mainly registers five key bean s in the spring container
1. ConfigurationClassPostProcessor: This is a very key class. I suggest you take a look at its source code. Basically, our custom bean s are registered through this class. The following annotations are processed in this class
@Configuration
@Component
@PropertySource
@PropertySources
@ComponentScan
@ComponentScans
@Import
@ImportResource
@Bean
2. AutowiredAnnotationBeanPostProcessor: responsible for processing @ Autowire annotations
3. Register CommonAnnotationBeanPostProcessor: responsible for processing @ Resource annotations
4. Register EventListener methodprocessor: the method responsible for processing the @ EventListener annotation, that is, the event processor
5. Register defaulteventlistener factory: it is responsible for wrapping the method of @ EventListener annotation as an applicationlister object
4. Stage 2 ~ stage 13
The 12 stages from stage 2 to stage 13 are all in the refresh method, so the refresh method is very important and needs more time to study this method.
The source code of refresh method is as follows:
org.springframework.context.support.AbstractApplicationContext#refresh @Override public void refresh() throws BeansException, IllegalStateException { // Phase 2: Spring Application context startup preparation phase prepareRefresh(); // Phase 3: BeanFactory Creation phase ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Phase 4: BeanFactory Preparation stage prepareBeanFactory(beanFactory); try { // Phase 5: BeanFactory post-processing phase postProcessBeanFactory(beanFactory); // Phase 6: BeanFactory register BeanPostProcessor stage invokeBeanFactoryPostProcessors(beanFactory); // Phase 7: Registration BeanPostProcessor registerBeanPostProcessors(beanFactory); // Phase 8: initialize built-in Bean: MessageSource initMessageSource(); // Phase 9: initialize built-in Bean: Spring Event broadcaster initApplicationEventMulticaster(); // Phase 10: Spring The application context refresh phase is implemented by subclasses onRefresh(); // Phase 11: Spring Event listener registration phase registerListeners(); // Phase 12: instantiate all remaining (non lazy init)Single case. finishBeanFactoryInitialization(beanFactory); // Stage 13: refresh completion stage finishRefresh(); } }
Stage 2: Spring application context startup preparation stage
protected void prepareRefresh() { // Mark start time this.startupDate = System.currentTimeMillis(); // Close: false this.closed.set(false); // Start: true this.active.set(true); // initialization PropertySource,Leave subclasses to implement. You can extend the attribute configuration information in this method and throw it to this.environment in initPropertySources(); // Verify whether the environment configuration contains the necessary configuration parameter information, for example, we want the context to start, this.environment You must configure some attributes in the to start it. You can verify it in this getEnvironment().validateRequiredProperties(); // earlyApplicationListeners Used to store early event listeners if (this.earlyApplicationListeners == null) { this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else { // Reset local application listeners to pre-refresh state. this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // earlyApplicationEvents Used to store early events this.earlyApplicationEvents = new LinkedHashSet<>(); }
What are early events? What are early event listeners?
When publishing events using the spring context, the following code
applicationContext.publishEvent(Event object)
The attribute under AbstractApplicationContext will eventually be used to publish events, but the applicationeventmulticast may not be created at this time and is an empty object, so events cannot be broadcast at this time. Then the publishing time is the early time and will be temporarily stored in this.earlyApplicationEvents. When the time broadcaster application The early events will not be broadcast until the eventmulticast is created
private ApplicationEventMulticaster applicationEventMulticaster;
Similarly, when the applicationeventmulticast is not ready and the following code is called to add an event listener to the spring context, the listener put in is the early event listener.
applicationContext.addApplicationListener(Event listener object)
After saying so much, it is easy to understand that when the event broadcaster applicationeventmulticast is not ready, the event added to the context is an early event, which will be put into this.earlyApplicationEvents. At this time, this event cannot be broadcast for the time being.
Phase 3: BeanFactory creation phase
This stage is responsible for creating the BeanFactory and returning it to the spring application context
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
obtainFreshBeanFactory source code:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //Refresh BeanFactory,Implemented by subclasses refreshBeanFactory(); //return spring Created in context BeanFacotry return getBeanFactory(); }
Phase 4: BeanFactory preparation phase
prepareBeanFactory(beanFactory);
The source code is as follows
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Set class loader beanFactory.setBeanClassLoader(getClassLoader()); // set up spel expression parser beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // Setting the Attribute Editor registrar beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // @1: Add a BeanPostProcessor: ApplicationContextAwareProcessor,When you bean Realized spring in xxxAware Such an interface, then bean During creation, the ApplicationContextAwareProcessor To call back these interfaces and inject objects into them beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // @2: During automatic injection, the methods defined by the following interfaces will be skipped. Why? Because these interfaces will be used by ApplicationContextAwareProcessor Back and forth injection beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // @3:The object to look up when registering dependency injection, such as your bean Want to use ResourceLoader,Then you can write:@Autowire private ResourceLoader resourceLoader,that spring The container will spring Container context injection beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // @4:Inject a beanpostprocessor: ApplicationListenerDetector beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // @5:take Environment Register to spring Container, corresponding bena The name is environment if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } // @6:Register system properties with spring Container, corresponding bean The name is systemProperties if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } // @7:Inject system environment variable configuration information into spring Container, corresponding bean The name is systemEnvironment if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
Let's take a look at @ 1's code first
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
An ApplicationContextAwareProcessor is injected into the spring container, which is a BeanPostProcessor (bean processor). Many methods are defined in this interface and will be called at different stages of bean creation, which is often used to extend the bean creation process. If you want to get to know a friend, you can take a look at this article first: Bean lifecycle.
After returning to the ApplicationContextAwareProcessor interface and looking at its source code, we can see what it does. As follows, when our bean implements an interface such as Aware, the methods in the interface will be called back to inject some objects in the spring context into the custom bean. For example, we use Environment in our bean, Then you only need to implement the EnvironmentAware interface, and the Environment will be injected automatically
if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }
Let's look at the code of * * @ 3 * *
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this);
This object is used to add dependency lookup to the spring container. The first line of the above code adds BeanFactory. When we want to use BeanFactory in our beans, we only need to write it as follows, and it will be automatically injected, even if the first line of the above code adds BeanFactory to the dependency lookup list
@Autowire private BeanFactory beanFactory;
Let's look at the code of @ 4
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
ApplicationListenerDetector is also a BeanPostProcessor. What is this class for? To handle custom event listeners.
When our bean implements the ApplicationListener interface and is an event listener, the bean creation process will be handled by ApplicationListenerDetector and our bean will be added to the event listener list of the spring context container.
Let's take a look at @ 5's code
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); }
Register the environment as a singleton in the singleton list of the spring container. The corresponding bena name is environment. When we need to use the environment in our beans, we can use the following writing method. At this time, in the process of creating beans, the spring container will find the environment from the singleton bean list and inject it into the following properties.
@Autowire private Environment environment
We can also find the environment object from the spring container through the environment name, as follows:
applicationContext.getBean("environment", Environment.class)
Let's look at the @ 6 and @ 7 codes
This code is the same as @5. Let's talk about it here
getEnvironment().getSystemProperties() -- corresponding --> System.getProperties()
getEnvironment().getSystemEnvironment() -- corresponding --> System.getenv()
Here's what System.getProperties() and System.getenv() do.
Everyone has used the following command. Let's mainly look at - D, which can set some startup parameters. These parameters followed by - D will be placed in System.getProperties().
java -jar -D parameter=value
System.getenv() is used to obtain the information of environment variables.
Stage 5: BeanFactory post-processing stage
postProcessBeanFactory(beanFactory);
This method is left for subclasses to implement. At this time, beanfactory has been created, but the beans in the container have not been instantiated. Subclasses can implement this method and make some special configurations for beanfactory, such as adding some custom beanpostprocessors, which are mainly left for subclasses to extend.
Phase 6: BeanFactory registers BeanPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
Call beanfactoryprocessor. What does beanfactoryprocessor do?
It is suggested to read this article first: Chapter 29 of Spring series: BeanFactory extension (beanfactoryprocessor, BeanDefinitionRegistryPostProcessor)
This stage is mainly to find all the implementation classes of the BeanFactoryPostProcessor interface from the spring container, then call to complete all bean registration functions. Note that bean registration is about to turn the definition information of bean into BeanDefinition object, and then register it into spring container. Bean is not instantiated, and continues below.
Let's look back at phase 1. Phase 1 registers a very key bean: ConfigurationClassPostProcessor in the spring container. The code is as follows
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); }
ConfigurationClassPostProcessor implements the beanfactoryprocessor interface, so ConfigurationClassPostProcessor will be called in phase 6. The following annotations are processed in this class. Therefore, if you want to study the principles of these annotations, you can directly look at the source code of ConfigurationClassPostProcessor, a very important class. Study the spring source code, Such must see
@Configuration
@Component
@PropertySource
@PropertySources
@ComponentScan
@ComponentScans
@Import
@ImportResource
@Bean
Generally, after the execution of phase 6, all our customized beans have been registered in the spring container, converted into BeanDefinition and thrown into BeanFactory. At this time, the beans have not been instantiated.
Phase 7: register the BeanPostProcessor
registerBeanPostProcessors(beanFactory);
Register the BeanPostProcessor. This stage will traverse the bean definition list of the spring container, roll out all beans that implement the BeanPostProcessor interface, and then add them to the BeanPostProcessor list of the spring container.
BeanPostProcessor is a bean post processor, which provides many methods to extend the process of bean creation.
Phase 8: initialize the built-in Bean: MessageSource
initMessageSource();
MessageSource is used to handle internationalization. At this stage, MessageSource will be created. If you want to expand or realize nationalization, you can see the source code of this method.
About internationalization, you can see this article: Spring series Chapter 26: internationalization details
Phase 9: initialize the built-in Bean: Spring event broadcaster
initApplicationEventMulticaster();
Applicationeventmulticast is an event broadcaster used to broadcast events. In this stage, applicationeventmulticast will be created. If you want to customize the event broadcaster, you can see the source code of this method. For the use of spring events, see here: Chapter 27 of spring series: detailed explanation of spring event mechanism.
Stage 10: Spring application context refresh stage, which is implemented by subclasses
onRefresh();
Used to initialize other special bean s, which are implemented by subclasses.
Phase 11: Spring event listener registration phase
registerListeners();
Register the event listener into the event broadcaster and see its source code as follows:
protected void registerListeners() { // @1:Register statically specified listeners first,soon spring Time listener added in context, added to time broadcaster( ApplicationEventMulticaster)in for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // @2:take spring The event listener defined in the container and added to the time broadcaster( ApplicationEventMulticaster)in String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // @3:At this time, the event broadcaster is ready, so the early events are published at this time (the early events are placed in the first place because the event broadcaster has not been created yet earlyApplicationEvents At this time, the broadcaster is created, so it will be released at an early time) Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
Here @1, add the event listener in the context to the event broadcaster. Just look at the source code below
org.springframework.context.support.AbstractApplicationContext Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>(); public Collection<ApplicationListener<?>> getApplicationListeners() { return this.applicationListeners; } @Override public void addApplicationListener(ApplicationListener<?> listener) { Assert.notNull(listener, "ApplicationListener must not be null"); if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.addApplicationListener(listener); } this.applicationListeners.add(listener); }
Let's take a look @3 at broadcasting early events. In the early stage, because the event broadcaster this.applicationeventmulticast is still empty, the events are placed in this.earlyApplicationEvents and are not broadcast. The early events are not broadcast until this time. Therefore, when using events, you should note that if you are before stage 11, If the following method is called to publish the event, you may not see the effect of the event at this time
applicationContext.publishEvent(Event object)
Therefore, if your bean implements the following interfaces, it is not recommended to implement the org.springframework.context.applicationlister interface, otherwise it will make you feel inexplicable.
org.springframework.beans.factory.config.BeanFactoryPostProcessor
org.springframework.beans.factory.config.BeanPostProcessor
Stage 12: instantiate all remaining (non lazy init) singletons
finishBeanFactoryInitialization(beanFactory);
All singleton beans will be instantiated in this method (beans that do not need to be instantiated later are not included). Let's look at the source code:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // add to ${}expression parser if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // Freeze all bean Definition that represents a registered bean The definition will not be further modified or post processed. This allows the factory to actively cache bean Define metadata. beanFactory.freezeConfiguration(); // @1: Instantiate all singletons bean(Does not contain any that require deferred instantiation bean),usually scope=singleton of bean Initialization will be completed in the following method. beanFactory.preInstantiateSingletons(); }
Focus on the code of @ 1. Here, you will call the preInstantiateSingletons() method of beanFactory to see the source code. The source code is located in the DefaultListableBeanFactory class, as follows:
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons public void preInstantiateSingletons() throws BeansException { // beanDefinitionNames Represents the current BeanFactory Defined in bean List of names, List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // @1: Loop instantiation bean for (String beanName : beanNames) { //Here according to beanName To instantiate bean,The code omits.... } // @2: variable bean,if bean Realized SmartInitializingSingleton Interface, which will be called afterSingletonsInstantiated()method for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; smartSingleton.afterSingletonsInstantiated(); } } }
The above method mainly does two things:
1. Complete the instantiation of all singleton beans: corresponding to the above code @1, cycle through the beanNames list to complete the instantiation of all singleton beans. After this cycle is completed, all singleton beans have been instantiated and cached in the spring container.
2. Callback to SmartInitializingSingleton interface: corresponding to the above code @2, all singleton beans have been instantiated. At this time, all singleton beans are traversed. If the bean implements the SmartInitializingSingleton interface, there is an aftersingleton instantiated method in this interface, this method will be called back. If we want to call back after all singleton beans are created, Do something to implement this interface.
Stage 13: refresh completion stage
finishRefresh();
Go in and see its source code
protected void finishRefresh() { // @1: Clean up some resource caches clearResourceCaches(); // @2: Initialize the lifecycle processor for this context initLifecycleProcessor(); // @3: First, the refresh is propagated to the lifecycle processor getLifecycleProcessor().onRefresh(); // @4: release ContextRefreshedEvent event publishEvent(new ContextRefreshedEvent(this)); }
Let's look at @ 2's code first
initLifecycleProcessor();
The source code is as follows
protected void initLifecycleProcessor() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //spring Is there a container named"lifecycleProcessor"of bean if (beanFactory.containsLocalBean("lifecycleProcessor")) { //from spring Found in container LifecycleProcessor,Endow this.lifecycleProcessor this.lifecycleProcessor = beanFactory.getBean("lifecycleProcessor", LifecycleProcessor.class); } else { //If spring There are no customizations in the container lifecycleProcessor,Then create a default DefaultLifecycleProcessor DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor(); defaultProcessor.setBeanFactory(beanFactory); //Set current spring Application context lifecycle processor this.lifecycleProcessor = defaultProcessor; //Register it with spring In container beanFactory.registerSingleton("lifecycleProcessor", this.lifecycleProcessor); } }
Let's look at the code of @ 3
getLifecycleProcessor().onRefresh();
Call the onRefresh method of the LifecycleProcessor. First, let's talk about the interface org.springframework.context.LifecycleProcessor. Two methods are defined in the lifecycle processor interface, and the onClose method will be called when the context is closed. You will see later
public interface LifecycleProcessor extends Lifecycle { /** * Context refresh notification */ void onRefresh(); /** * Context close notification */ void onClose(); }
Let's take a look at the onRefresh method. This interface has a default implementation org.springframework.context.support.defaultlifecycle processor, so by default, we'll look at the onRefresh source code in defaultlifecycle processor, as follows
public void onRefresh() { startBeans(true); this.running = true; }
Look inside the startBeans(true). As follows, the code may seem to be a little bit winding. In fact, it is very simple to find all bean that implements the org.springframework.context.Lifecycle interface from the container, and then call their start method.
private void startBeans(boolean autoStartupOnly) { Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); Map<Integer, LifecycleGroup> phases = new HashMap<>(); lifecycleBeans.forEach((beanName, bean) -> { if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) { int phase = getPhase(bean); LifecycleGroup group = phases.get(phase); if (group == null) { group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly); phases.put(phase, group); } group.add(beanName, bean); } }); if (!phases.isEmpty()) { List<Integer> keys = new ArrayList<>(phases.keySet()); Collections.sort(keys); for (Integer key : keys) { phases.get(key).start(); } } }
Let's look at the code of @ 4
publishEvent(new ContextRefreshedEvent(this));
Publish the ContextRefreshedEvent event. If you want to do something at this stage, you can listen to this event.
Summary
There are three main tasks in this stage:
1. Initializes the lifecycle processor in the current context.
2. Call the LifecycleProcessor.onRefresh() method. If there is no custom LifecycleProcessor, the DefaultLifecycleProcessor will be used, and the start method of all bean s implementing the Lifecycle interface in the spring container will be called.
3. Publish the ContextRefreshedEvent event.
4. Stage 14: Spring application context closing stage
applicationContext.close()
Finally, you will enter the doClouse() method, and the code is as follows
org.springframework.context.support.AbstractApplicationContext#doClose protected void doClose() { // Determine whether it needs to be closed( active by tue It can be closed and used cas Ensure that only one execution is successful in the case of concurrency) if (this.active.get() && this.closed.compareAndSet(false, true)) { //@1: Publish close event ContextClosedEvent publishEvent(new ContextClosedEvent(this)); // @2: Calling the lifecycle processor onClose method if (this.lifecycleProcessor != null) { this.lifecycleProcessor.onClose(); } // @3: Destroy context BeanFactory Singleton of all caches in destroyBeans(); // @4: close BeanFactory itself closeBeanFactory(); // @5: Just extend it to subclasses onClose(); // @6: Restore the event listener list to the state before refreshing, that is, restore the previous event listener if (this.earlyApplicationListeners != null) { this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // @7: Tag activity status is: false this.active.set(false); } }
Let's first look at the code of @ 1
publishEvent(new ContextClosedEvent(this));
Publish the ContextClosedEvent event.
Let's look at the code of @ 2
if (this.lifecycleProcessor != null) { this.lifecycleProcessor.onClose(); }
Call the onClose method of the lifecycle processor. Here, let's directly look at the onClose() of defaultlifecycle processor to see its source code, as follows
public void onClose() { stopBeans(); //take running Set to false this.running = false; }
The stopBeans() source is as follows: a large piece of simple understanding: find all the bean that implements the org.springframework.context.Lifecycle interface from the container, then call their close() method.
private void stopBeans() { Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); Map<Integer, LifecycleGroup> phases = new HashMap<>(); lifecycleBeans.forEach((beanName, bean) -> { int shutdownPhase = getPhase(bean); LifecycleGroup group = phases.get(shutdownPhase); if (group == null) { group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false); phases.put(shutdownPhase, group); } group.add(beanName, bean); }); if (!phases.isEmpty()) { List<Integer> keys = new ArrayList<>(phases.keySet()); keys.sort(Collections.reverseOrder()); for (Integer key : keys) { phases.get(key).stop(); } } }
Let's look at the code of @ 3
destroyBeans();
Destroying all cached singleton beans in the context BeanFactory mainly involves two things:
1. Calling the bean's destruction method
For example, the bean implements the org.springframework.beans.factory.DisposableBean interface, which will be called at this time. In addition, some methods in the bean annotated with @ PreDestroy annotation will also be called at this time.
2. Clean up the bean information from the BeanFactory
Let's look at the code of @ 4
closeBeanFactory();
The source code is as follows, mainly to restore the beanFactory attribute in the current spring application context.
org.springframework.context.support.AbstractRefreshableApplicationContext#closeBeanFactory @Override protected final void closeBeanFactory() { synchronized (this.beanFactoryMonitor) { if (this.beanFactory != null) { this.beanFactory.setSerializationId(null); this.beanFactory = null; } } }
5. Summary
This paper introduces the life cycle of spring application context in detail. It is very important. There are a little more contents and details. It is recommended that you read it several times in combination with the source code. When you are free, you can also look back a few times to deepen your understanding. If you have problems, you are welcome to leave a message.
6. Case source code
git Address: https://gitee.com/javacode2018/spring-series
Let's star, all the series codes will be in this, and the links of all original articles are also in it, which is convenient to check!!!
Source: https://mp.weixin.qq.com/s?__ biz=MzA5MTkxMDQ4MQ==&mid=2648939152&idx=2&sn=2177e513f51d8127c4c468be07515631&scene=21#wechat_ redirect