Spring source code-automatic injection

In the previous blog, the principles of @Autowired and @Resource annotations were introduced. We consider these two methods to be manual injection, which is the default injection method of spring. If we want to use automatic injection, we need to set the automatic injection mode autowireMode

1. Application

@Component
public class UserBean {
    
    

    private IndexBean indexBean;

    public UserBean(IndexBean indexBean) {
    
    
        System.out.println("userBean带参构造函数");
        this.indexBean = indexBean;
    }

    public UserBean(){
    
    
        System.out.println("userBean空参构造函数");
    }

    public void setIndexBean123(IndexBean indexBean) {
    
    
        System.out.println("setIndexBean123方法注入属性");
        this.indexBean = indexBean;
    }

    public void setIndexBean(IndexBean indexBean){
    
    
        System.out.println("setIndexBean方法执行,这是通过类型自动注入时会执行的代码");
        this.indexBean = indexBean;
    }

    public void test() {
    
    
        System.out.println("注入的indexBean属性是:" + indexBean);
    }
}

This is to modify the automatic injection mode corresponding to the bean through the BeanFactoryPostProcessor

/* 修改beanDefinitionRegistry注入模型有多种方式:
 *  1.在BeanFactoryPostProcessor的实现类中进行修改
 *  2.在ImportBeanDefinitionRegistrar的实现类中进行修改
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
            throws BeansException {
    
    
        GenericBeanDefinition userBean = (GenericBeanDefinition) configurableListableBeanFactory
                .getBeanDefinition("userBean");
        System.out.println("默认的autowireMode是:" + userBean.getAutowireMode());
        userBean.setAutowireMode(1);
    }
}

Automatic injection model, the default is 0, need to be injected through @Autowired or @Resource annotation; if it is non-zero, these two annotations may not be provided

  • autowire_no(0): The default assembly mode, if the injected indexBean does not add @Autowired or @Resource, at this time, indexBean cannot be injected
  • autowire_name(1): through the set method, and the name of the set method must be consistent with the name of the bean, byName
  • autowire_type(2): Through the set method, the set method can be named arbitrarily, and the bean is injected according to the input parameter type, byType
  • autowire_constructor(3): Inject through the constructor, if indexBean is injected into userBean, then a constructor with indexBean must be provided, otherwise it is null

Execution result:
Scenario where autowireMode is 1:

userBean空参构造函数
setIndexBean方法执行,这是通过类型自动注入时会执行的代码

The scenario where autowireMode is 2:

userBean空参构造函数
setIndexBean方法执行,这是通过类型自动注入时会执行的代码
setIndexBean123方法注入属性

AutowireMode is this scenario of 3:

userBean带参构造函数

As for the scenario where the autowireMode is 3, this note will not be recorded for the time being, because it involves the second post processor, inferring the logic of the constructor, here I have not fully understood it, so this note will not be recorded for the time being , After learning the execution logic of the second post processor, record together

Second, the source code

2.1 Conclusion

We have said before that the fifth post processor is to determine whether attribute injection is required, and the sixth post processor is to complete attribute injection. What needs to be explained here is: For manual injection (@Autowired, @Resource) , The attribute injection is completed in the sixth post processor.
But for automatic injection (autwireMode is 1, 2), this kind of
1, is between the fifth post processor and the sixth post processor In a piece of code, the judgment of the attributes to be injected is completed
2, and then after the execution of the sixth post processor is completed, the attribute injection is completed through method.invoke(), which is to call the set method provided by the programmer.
3. For automatic injection The way, the sixth post processor will not do task processing, there is an important line of code after the sixth post processor, which completes the method.invoke() method call

第五个后置处理器
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation

第六个后置处理器
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessPropertyValues

2.2 Find which beans need to be injected into the current bean

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

For automatic injection: autowire_name and autowire_type are all done in the populateBean method

/**
 * 首先解释一个名词:@Autowired和@Resource,我们通常称之为自动注入,@Autowired注解先根据name找,再根据type找,这样说,其实不严谨
 * 我们姑且先认为@Autowired和@Resource是手动注入,并且这里的先根据name,再根据type找的这个说发,会在后面进行解释
 * 我们认为将AutowireMode注入模型设置为AUTOWIRE_BY_NAME/AUTOWIRE_BY_TYPE/AUTOWIRE_CONSTRUCTOR的为自动注入
 *
 * 下面代码开始,就是完成注入的,spring在这里完成注入,可以大致分为两个类型:
 * 自动注入:
 *	下面的newPvs是根据自动注入模型找到的要注入的属性,然后再下面(applyPropertyValues(beanName, mbd, bw, pvs);),会进行统一的注入
 *
 *
 * 手动注入:
 * 	在上面一行代码中,获取到程序员手动在代码中声明的要注入的属性
 * 	ac.getBeanDefinition("ccc").getPropertyValues().add("name","mpyTest"); 这种就是在代码中手动声明要注入的属性
 *	在后置处理器中,根据@Autowired注解或者@Resource注解,获取到要注入的属性
 *
 * 	对于手动注入,我们所说的byType并不是从单实例池中根据类型查找的,而是从beanDefinitionMap中查找的
 *
 *
 * spring默认的注入模型是 AUTOWIRE_NO
 *
 */
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
    
    
	MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
	// Add property values based on autowire by name if applicable.
	if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
    
    
		autowireByName(beanName, mbd, bw, newPvs);
	}
	// Add property values based on autowire by type if applicable.
	//这里是判断当前bean需要注入哪些属性的
	if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
    
    
		autowireByType(beanName, mbd, bw, newPvs);
	}
	pvs = newPvs;
}

Explain in advance: The above piece of code is just to find the bean to be injected. The completion of the attribute injection is in the following piece of code, which will be introduced separately. This is part of the code in populateBean(). Let’s look at the different lookups of autowire_name and autowire_type. Inject the logic of the bean

2.3 autowire_name

So: for the injection mode is name, we have to focus on the autowireByName() method

protected void autowireByName(
		String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    
    

	/**
	 * 这里的propertyNames就是获取到所有的set方法对应的方法名,底层是通过writeMethod来判断的
	 * 下面的containsBean(propertyName)是来判断获取到的beanName是否存在于单实例池中或者beanDefinitionMap中
	 *
	 * 如果自动注入模型是autowire_byname,但是提供的set方法没有参数,是空参,那这里是获取不到的;这里应该和Java的内省机制有关系
	 */
	String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
	for (String propertyName : propertyNames) {
    
    
		/**
		 * 在截取到所有set方法对应的beanName之后,会判断一下beanName是否存在于单实例池中或者beanDefinitionMap中,
		 * 如果存在,就调用getBean(),从单实例池中获取bean或者初始化bean
		 * 如果不存在,就无需注入
		 */
		if (containsBean(propertyName)) {
    
    
			/**
			 * getBean()这个方法我个人感觉就可以说明autowire_name是根据名字来注入属性的,这里是真正的从单实例池中查询对象的
			 * 这里的propertyName就是set方法对应的name
			 *
			 * 获取到bean之后,会存入到pvs中,在后面进行是注入的时候,会用到pvs
			 */
			Object bean = getBean(propertyName);
			pvs.add(propertyName, bean);
			registerDependentBean(propertyName, beanName);
		}
	}
}

The unsatisfiedNonSimpleProperties() method is to find all the set methods in the current bean, and then filter them out, the set method provided by the programmer

protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
    
    
	Set<String> result = new TreeSet<>();
	PropertyValues pvs = mbd.getPropertyValues();
	/**
	 * 获取到当前bean中所以设置属性的方法和获取属性的方法:就是getXXX,和setXXX
	 * 在下面这行代码执行的时候,有一个很重要的概念:设置当前方法的parameterType类型,我觉得可以理解为当前方法的入参对应的类型
	 * org.springframework.core.MethodParameter#getParameterType(); 在这个方法中设置的
	 */
	PropertyDescriptor[] pds = bw.getPropertyDescriptors();
	for (PropertyDescriptor pd : pds) {
    
    
		//判断哪些属性是不需要自动注入的;在Java中,方法可以分为读方法(readMethod)和写方法(writeMethod)
		if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
				!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
    
    
			result.add(pd.getName());
		}
	}
	return StringUtils.toStringArray(result);
}

This method is a logic that both autowire_type and autowire_name will call. I have not understood some of the judgment conditions in this method, but after this method is executed, the method name corresponding to the set method provided by the programmer will be obtained
Insert picture description here

Let's look at the operation after obtaining the method name corresponding to all the set methods provided by the programmer.
1. containsBean(propertyName); In this method, the method name will be used as the beanName and judged from the bean single-instance pool or beanDefinitionMap. Whether the beanName exists, if it exists, return true, return false, indicating that no injection is required.
2. If the beanName corresponding to the current set method name exists in the single-instance pool, it is obtained or initialized from the single-instance pool, and getBean() is performed Initialization logic
3. Then put the properties to be injected into the property MutablePropertyValues ​​pvs. When method.invoke is executed later, it is related to this property.

2.4 autowire_type

For this method, we should focus on the autowireByType(beanName, mbd, bw, newPvs); method in 2.2

protected void autowireByType(
		String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    
    

	TypeConverter converter = getCustomTypeConverter();
	if (converter == null) {
    
    
		converter = bw;
	}

	Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
	/**
	 * 这行代码是获取到当前bean中所有的writeMethod方法,个人理解,就是set方法对应的集合
	 * 根据类型自动注入的时候,会获取到set方法的参数
	 */
	String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
	for (String propertyName : propertyNames) {
    
    
		try {
    
    
			PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
			// Don't try autowiring by type for type Object: never makes sense,
			// even if it technically is a unsatisfied, non-simple property.
			if (Object.class != pd.getPropertyType()) {
    
    
				MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
				// Do not allow eager init for type matching in case of a prioritized post-processor.
				boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
				/**
				 * 在这里的desc对象中,有一个parameterTypes数组,存储的是当前方法的入参对应的bean类型,
				 * 对于autowire_type这种模式,入参就是需要注入的类型
				 */
				DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
				/** 
				 * 这个方法中,会根据beanName去加载;这里的desc,就是bean中的set方法名,比如 setIndexBean123
				 * 这个方法返回的就是根据type找到的要注入的bean,下面要调用的这个方法,在@Autowired注解中也会调用
				 */
				Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
				if (autowiredArgument != null) {
    
    
					pvs.add(propertyName, autowiredArgument);
				}
				for (String autowiredBeanName : autowiredBeanNames) {
    
    
					registerDependentBean(autowiredBeanName, beanName);
					if (logger.isDebugEnabled()) {
    
    
						logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
								propertyName + "' to bean named '" + autowiredBeanName + "'");
					}
				}
				autowiredBeanNames.clear();
			}
		}
		catch (BeansException ex) {
    
    
			throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
		}
	}
}

The method here, you will see, also first obtain the method name corresponding to all the set methods, and then initialize a PropertyDescriptor according to the method name, etc. The key thing is to look at the resolveDependency() method. This method and the @Autowired annotation are parsed The use of a common method

Here I actually didn’t fully understand the role of sharing a piece of code:
my understanding is: whether it is @Autowired or autowire_type, since it is based on type injection, it will involve a scenario of multiple implementation classes of one type, after all, it is necessary to parse out one. Implementation class with higher priority, so it shares a judgment logic

Here, when the corresponding injected bean is found, it will also be placed in pvs

2.5 attribute injection

At the end of populateBean(), there are two lines of code

/**
 * 在这里有一个点,需要明白:
 *  1.@Autowired和@Resource注解注入的方式我们可以理解为手动注入;通过设置AutowiredModel的形式是自动注入
 *  2.手动注入的属性,是在上面 ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); 这里完成的属性填充
 *    对于自动注入的以及程序员自己提供的待注入属性,是在下面这行代码完成的属性填充
 *    通过method.invoke()方法完成
 *  3.第三次调用后置处理器,查到的是手动注入的注解,需要注入的属性,手动注入是通过field.set()来完成的属性注入;自动注入是通过method.invoke()完成的
 */
if (pvs != null) {
    
    
	applyPropertyValues(beanName, mbd, bw, pvs);
}
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyPropertyValues
	org.springframework.beans.PropertyAccessor#setPropertyValues(org.springframework.beans.PropertyValues)
		org.springframework.beans.AbstractPropertyAccessor#setPropertyValue(org.springframework.beans.PropertyValue)
			org.springframework.beans.AbstractNestablePropertyAccessor#setPropertyValue(org.springframework.beans.AbstractNestablePropertyAccessor.PropertyTokenHolder, org.springframework.beans.PropertyValue)
				org.springframework.beans.AbstractNestablePropertyAccessor#processLocalProperty
					org.springframework.beans.AbstractNestablePropertyAccessor.PropertyHandler#setValue
						

Finally, method.invoke() will be used to call the corresponding set method to complete the attribute injection

3. Conclusion

For autowire_name:
1. According to all the set methods provided in the bean, find the corresponding method name, for example: I provide setIndexBean123(); setIndexBean();
2. Spring will get the two properties of indexBean123 and indexBean
3. After obtaining these two properties, determine whether the beanName exists from the single-instance pool or beanDefinitionMap.
4. If it exists, try to get or initialize the bean from the single-instance pool, and then store the beanName and the corresponding bean to be injected into In an object: MutablePropertyValues
5. After calling the sixth post processor, property injection will be completed through method.invoke()

For autowire_type:
1. According to the set method provided in the bean, find the method name corresponding to the method, for example: I provide setIndexBean123(); setIndexBean();
2. Spring will get the two properties of indexBean123 and indexBean
3. Then according to the input parameter type corresponding to the method, here is the difference with autowire_name, here is according to the input parameters of the method, from the beanDefinitionMap, sequentially determine whether the attribute to be injected exists
4. If it exists, try from the single instance pool Get or initialize the bean, and then store the beanName to be injected and the corresponding bean in an object: MutablePropertyValues
5. After calling the sixth post processor, the property injection will be completed through method.invoke()

So:
for manual injection (@Autowired, @Resource), attribute injection is completed in the sixth post processor, and
for automatic injection through field.set, attribute injection is completed through method.invoke(), that is, execution The corresponding set method, for this method of automatic injection, will not do any processing when the sixth post processor is executed

Guess you like

Origin blog.csdn.net/CPLASF_/article/details/109776990