spring's path to God Chapter 55: spring context life cycle

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

 

Posted on Sun, 07 Nov 2021 12:47:16 -0500 by neex1233