[Spring] Bean life cycle source code analysis preparatory work before instantiation

test beans

image-20220402195218252

1. Container startup

There are many ways for Spring to create a container. It can be based on configuration classes or based on xml configuration files. Here, we use XML configuration to create Spring containers.

Debug starts and sets the first breakpoint

image-20220402195444899

image-20220402195512957

Come to org.springframework.context.support.AbstractApplicationContext.refresh() method refresh is the core method of spring container startup

A total of 12 other methods are called in this method. This article is to look at the life cycle of Beans. All unrelated methods are briefly explained.

image-20220402200031113

The first method prepareRefresh()

// Prepare this context for refreshing.
prepareRefresh();

image-20220402200138646

image-20220402200411029

Next, this line of code is executed to do a very important thing, create a BeanFactory

// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

2. Create BeanFactory

Let's see how to get the bean factory

image-20220402201013476

debug跟进 org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory

image-20220402201203774

image-20220402201225691

return new DefaultListableBeanFactory(getInternalParentBeanFactory());

The returned bean factory type is DefaultListableBeanFactory

If you download the source code, you can see the full set of bean lifecycle interfaces annotated in the BeanFactory interface, etc. We can see them all in the source code

Bean factory implementations should support standard bean lifecycle interfaces whenever possible. The full set of initialization methods and their standard sequence are:

  1. BeanNameAware's setBeanName

  2. BeanClassLoaderAware’s setBeanClassLoader

  3. BeanFactoryAware’s setBeanFactory

  4. EnvironmentAware’s setEnvironment

  5. EmbeddedValueResolverAware's setEmbeddedValueResolver

  6. ResourceLoaderAware’s setResourceLoader (only applicable when running in an application context)

  7. ApplicationEventPublisherAware’s setApplicationEventPublisher (only applicable when running in an application context)

  8. MessageSourceAware’s setMessageSource (only applicable when running in an application context)

  9. ApplicationContextAware’s setApplicationContext (only applicable when running in an application context)

  10. ServletContextAware’s setServletContext (only applicable when running in a web application context)

  11. postProcessBeforeInitialization methods of BeanPostProcessors

  12. InitializingBean’s afterPropertiesSet

  13. a custom init-method definition

  14. postProcessAfterInitialization methods of BeanPostProcessors

When closing the bean factory, the following lifecycle methods are applied:

  1. postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
  2. DisposableBean’s destroy
  3. a custom destroy-method definition

回到 org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory

image-20220402202023699

After creating the bean factory, three more methods are called

Method 1: Set serialization ID

beanFactory.setSerializationId(getId());

Method 2: Customize the bean factory (whether the bean definition can be overridden, whether to run circular dependencies)

customizeBeanFactory(beanFactory);

image-20220402202227244

Method 3: Parse the bean configuration information and generate BeanDefinitions (hereinafter referred to as bd)

loadBeanDefinitions(beanFactory);

3. Parse and generate BeanDefinitions

debug跟进 来到 org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions()

image-20220402202549429

	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

Create an xml parser, we use the xml configuration file to start the container, and the bean definition information is configured in xml

image-20220402204904250

After the parsing is complete, call the loadBeanDefinitions(beanDefinitionReader) method and add it to the BeanDefinition

image-20220402203818866

Next, get all the configuration information files and load them

String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}

image-20220402203945173

Finally, the xml configuration file is parsed into a Document object through JAXP in the JDK, and then registered as bd

After registering bd, the beanDefinitionMap in the beanFactory already has the definition information of bean A. In the future, through these definition information, a bean A can be initialized and placed in the container by reflecting the instance.

image-20220402205004034

image-20220402205119334

Next, come to the invokeBeanFactoryPostProcessors(beanFactory) method to enter the post-processor process of executing the Bean Factory

4. Execute the post-processor method of the Bean factory

image-20220402205718893

The execution time of the post-processor method of the bean factory is to initialize bean factory, and after parsing and generating bd, but before the bean is instantiated

Then the refresh method goes down, and the eleventh method begins to enter the instantiation phase of the bean

finishBeanFactoryInitialization(beanFactory)

5. ApplyBeanPostProcessorsBeforeInstantiation extension point before instantiating the bean

来到 org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization

​ Called beanFactory.preInstantiateSingletons(); to initialize all single instance beans

​ org.springframework.beans.factory.support.DefaultListableBeanFactory. preInstantiateSingletons()

image-20220402210730029

First copy all beanNames and put them in beanNames

List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

Then start traversing all beanNames

for (String beanName : beanNames) {
			.....

}

The first step of traversal is to convert bd to RootBeanDefinition to unify

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

Then there is a triple judgment that it cannot be an abstract class, it must be a singleton, and it is not lazy loading, and continue to go down

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				

Determine whether it is a factory bean test bean A is a common bean, go else

if (isFactoryBean(beanName))

Call getBean(beanName); method

​ 又调用 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean

image-20220402211356894

First get the real beanName, remove the & prefix of the factory bean name and resolve the bean alias

String beanName = transformedBeanName(name);

Then try to get the bean object from the cache

Object sharedInstance = getSingleton(beanName)

来到 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton

First note the parameters of a method call

image-20220402211745945

allowEarlyReference 这个参数的值,默认就是true,用来解决循环依赖的,很重要

Then look at this method from the first-level cache, the first-level cache is full and initialized singleton bean, if you can get it, return directly

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256) Singleton cache pool (first level cache)

Object singletonObject = this.singletonObjects.get(beanName); //singletonObjects  单例缓存池

If not, and the bean corresponding to the current beanName is being created

private final Set singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)) saves the beanName being created

if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {

Find in earlySingletonObjects from the second level cache

private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16) Second-level cache, instantiated, but not filled with properties

singletonObject = this.earlySingletonObjects.get(beanName);

If not found, continue to search from the third-level cache singletonObjects

**private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16) stores the lombda expression that generates the proxy object**

Note that the value ObjectFactory<?> of this map is a functional interface, which will be used to save lombda expressions in the future to solve the problem of circular dependencies of beans proxied by AOP

image-20220402212956053

ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);

If the singletonFactory is not empty, the lombda expression will be executed to generate a proxy class, that is, AOP in advance

singletonObject = singletonFactory.getObject();

image-20220402213614956

After AOP in advance, two interesting methods are executed

Put the current proxy class object into the second-level cache, and then delete the entry in the third-level cache. These two steps are very important. Later, I will write a circular dependency blog post, which will explain in detail.

If you don't get it from the cache, return an empty object directly

image-20220402213819171

image-20220402215143093

Circular dependency judgment, there is no circular dependency problem, go down, objects with circular dependencies first create dependent objects

image-20220402214942619


The current bean is a singleton, enter if

sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});

A getSingleton method is called here. The method has two parameters, a beanName, and a lombda expression,

执行org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法

image-20220402215320614

First verify that the name of the bean cannot be empty

Assert.notNull(beanName, "Bean name must not be null");

Then try to get the object from the cache again and see it

Object singletonObject = this.singletonObjects.get(beanName);

image-20220402215613991

I didn't get to enter the if judgment to execute the lombda expression

image-20220402215637234

Execute createBean(beanName, mbd, args); method

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

image-20220402215838411

Before the bean is actually instantiated, there is also such a method to return the current proxy object instead of the target bean object

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd)

image-20220402220049094

Determine whether there are InstantiationAwareBeanPostProcessors in the container, and if so, execute the InstantiationAwareBeanPostProcessors.applyBeanPostProcessorsBeforeInstantiation method

image-20220402220213636

InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation is called before instantiation

Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);

If there is a return object, the changed object will be placed in the spring container, and the instantiation process of the bean to which the current bd package definition information belongs will be terminated early, and the InstantiationAwareBeanPostProcessor.applyBeanPostProcessorsAfterInitialization method will be executed.

image-20220402220415687

If null is returned, the current bean instantiation process continues down

We did not implement the applyBeanPostProcessorsBeforeInstantiation extension point, and continue to go down

image-20220402220559678

Come to the doCreateBean(beanName, mbdToUse, args) method

doCreateBean(beanName, mbdToUse, args)

The process before the bean instantiation has been completed, and the actual bean instantiation has begun to be placed in the next blog post

Guess you like

Origin blog.csdn.net/JAVAlife2021/article/details/123930142