[Spring source code series (1)] Bean life cycle

Bean life cycle in Spring

1. What is Bean?

All objects that are instantiated, assembled and managed by the Spring IoC container are called Bean objects. The Bean object itself can be thought of as a Pojo.

The official website explains:

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.

2. Bean life cycle

image-20210913125107850

2.1, BeanDefinition reading & parsing

We can configure beans through XML or configuration annotations. This stage is in charge of the BeanDefinitionReader interface, which is implemented by its implementation class.

image-20210911162504718

On the other hand, Spring's configuration file reading is defined through the Resource interface:

image-20210911165210092

Summary: File Parsing Process

  • Get the validation mode for the XML file; (DTD and XSD methods, indicated in the file header)
  • Load the XML file to get the corresponding Document;
  • Register Bean information according to Document.

2.2, BeanDefinition registration & loading

Through the above methods, we obtain Document and resolve it to BeanDefinition, register it through DefaultListableBeanFactory#registerBeanDefinition, the only real implementation subclass of BeanDefinitionRegistry, and store it in beanDefinitionMap.

At the same time, this process also involves the merging and conversion of BeanDefinitions, such as passing RootBeanDefinition and ChileBeanDefinition that have a parent-child relationship through

The DefaultListableBeanFactory#getMergedBeanDefinition methods are merged into a final RootBeanDefinition. Because the parsed BeanDefinition exists in the form of GenericBeanDefinition, a further conversion is required.

What is a father-son relationship? That is, beans can be inherited, and subclasses have the properties of the parent class.

image-20210908211914787

Have you ever thought about why we need BeanDefinition, what we need is Bean Factory in principle.

In fact, there is an Object beanClass in BeanDefinition; through AbstractBeanFactory#resolveBeanClass, the object type object is converted into a class type for subsequent instantiation.

2.3, Bean instantiation

2.3.1, before bean instantiation

Before instantiation, you can implement BeanFactoryPostProcessor#postProcessBeanFactory, and overwrite and increase the properties of the read BeanDefinition according to the priority order. (Note that the Bean object cannot be obtained in advance, which will cause the Bean to be initialized in advance.)

This process is equivalent to an extension to BeanFactory.

2.3.2, Bean instantiation

image-20210912154930958
image-20210911192823752
image-20210912175005544
At this stage, many operations involving InstantiationAwareBeanPostProcessor will be interspersed in the process of instance Bean. We mainly look at the calling mechanism of its implementation method.

First, through the method AbstractAutowireCapableBeanFactory#createBean#doCreateBean#createBeanInstance, there will be different instance strategies for different beans:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    
    
		// BeanDefinition 加载获得类对象
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
    
    
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
    
    
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		//1,如果 factory-method 属性不为空,则使用 factory-method 方式实例化
		if (mbd.getFactoryMethodName() != null)  {
    
    
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
    
    
			synchronized (mbd.constructorArgumentLock) {
    
    
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
    
    
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
    
    
			if (autowireNecessary) {
    
    
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
    
    
				return instantiateBean(beanName, mbd);
			}
		}

		//2,决定候选的构造器实例化 bean...
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
    
    
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		//3, 否则指向默认的无参构造策略:
    	   //最终通过 BeanUtils#instantiateClass 调用 ctor.newInstance 方法反射创建
		return instantiateBean(beanName, mbd);
	}

Of course, for a dependent bean, the instantiation of the dependent bean can be realized through the post-enhancer. The processing principle is to implement the dependent bean first, and then instantiate the bean.

The point is that the enhancement operation can be performed in the instantiation phase, specifically by calling the enhancement operation in resolveBeforeInstantiation in the AbstractAutowireCapableBeanFactory#creatBean method. If the return is not empty, the instantiation operation of the bean will be completed directly and exit; if the return is empty, enter The upper-level createBean method executes doCreateBean and continues to complete the normal execution process of spring.

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
    
    
			//省略。。。。。
try {
    
    
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
    
    
				return bean;
			}
		}
}

The resolveBeforeInstantiation here performs the enhancement operations before and after the instantiation of applyBeanPostProcessorsBeforeInstantiation and applyBeanPostProcessorsAfterInitialization respectively. It can be seen that if the enhancement is made before instantiation, the post-instantiation and pre-initialization operations will be skipped, and the Bean object will be created directly. The next stage will be attribute population.

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    
    
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    
    
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    
    
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
    
    
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
    
    
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

As mentioned above, when our resolveBeforeInstantiation returns empty, the instance of the object will be executed normally, and the doCreateBean method is triggered:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)	throws BeanCreationException {
    
    
	// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
    
    
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
    
    
            //如果 bean 实例未被创建,先创建 bean,这里调用 createBeanInstance 又回到了上面
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
// Initialize the bean instance.
		Object exposedObject = bean;
		try {
    
    
            		//属性赋值
			populateBean(beanName, mbd, instanceWrapper);
            		//initializeBean 进去便触发我们的初始化方法
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}

Let's look at populateBean again:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    
    
	// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
		// state of the bean before properties are set. This can be used, for example,
		// to support styles of field injection.
		boolean continueWithPropertyPopulation = true;

		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    
    
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
    
    
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
    
    
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					//实例化后置处理器(属性赋值也被认为是实例化阶段)
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    
    
						continueWithPropertyPopulation = false;
						break;
					}
				}
			}
		}

summary:

The pre- and post-initialization methods defined by BeanPostProcessor will trigger the pre-processor in resolveBeforeInstantiation; or trigger the pre- and post-processor in initializeBean.

The method defined by InstantiationAwareBeanPostProcessor will trigger the pre-processor by resolveBeforeInstantiation and the post-processor by populateBean during the instantiation process.

2.3.3, attribute assignment

This step is for property filling, specifically getPropertyValues ​​in InstantiationAwareBeanPostProcessor#populateBean. This method will finally complete the attribute injection of the tag property configuration in the xml by calling the Filed.set method.

Two other implementations of this method:

AutowiredAnnotationBeanPostProcessor injects values ​​into fields and methods annotated with @Autowired and @Value in this method.

CommonAnnotationBeanPostProcessor injects values ​​into @Resource annotated fields and methods in this method.

2.4, Bean initialization

2.4.1, before Bean initialization

The sequence of calls in AbstractAutowireCapableBeanFactory#initializeBea for this procedure:

  • Preprocessor for applyBeanPostProcessorsBeforeInitialization#postProcessBeforeInitialization
  • invokeInitMethods #initialization method
  • post-processor for applyBeanPostProcessorsAfterInitialization#postProcessAfterInitialization

2.4.2, Bean initialization

Call the InitializingBean#afterPropertiesSet method;

Then call the initialization method specified when defining the bean

Beans know how to initialize methods:

Mode 1: Specify the initialization method in xml mode

Method 2: Specify the initialization method in the way of @Bean

@Bean(initMethod = "Initialization method")

Method 3: Specify the initialization method in the way of api

this.beanDefinition.setInitMethodName(methodName);

2.4.3, after bean initialization

Call the postProcessAfterInitialization method of the BeanPostProcessor interface.

2.5, Bean usage

Call the getBean method directly.

2.6, Bean destruction

Polling the list of beanPostProcessors, if it is the type of DestructionAwareBeanPostProcessor, its internal postProcessBeforeDestruction method will be called;

If the bean implements the org.springframework.beans.factory.DisposableBean interface, the destroy method in this interface will be called;

Call the bean's custom destroy method.

3. Interview

3.1,FactoryBean

Sometimes it is very complicated to instantiate a Bean, if it has more properties, it needs to configure a lot of information. The way of creating beans using the factory BeanFactory will strictly enforce the life cycle, which brings many inconveniences. To do this, you can customize the instantiation bean logic by implementing the FactoryBean interface.

When we set the bean's class attribute to the FactoryBean interface type in the configuration file, the bean obtained by the getBean method is not the FactoryBean itself but the object returned by the FactoryBean#getObject() method, and there is a proxy here. If you need to get the FactoryBean instance object, you need to explicitly perform getBean(&beanName).
In short, FactoryBean is a small factory and BeanFactory is a root factory.

3.2, L3 cache solves circular dependencies

	/** Cache of singleton objects: bean name --> bean instance */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name --> ObjectFactory */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name --> bean instance */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

image-20210911193815106

Guess you like

Origin blog.csdn.net/qq_40589204/article/details/120315143