Spring自动装配源码分析

news2024/10/3 10:40:10

写在前面:阅读spring源码需要读者对Java反射和动态代理有一定了解。关于这部分内容,可以参考这篇博客:Spring源码分析准备工作及java知识补充

一、Spring依赖注入的方式

        关于spring的依赖注入,可以参考官方文档:Spring依赖注入

        Spring中的依赖注入主要基于两种两种主要的变体: 基于构造器的依赖注入和基于Setter的依赖注入。

(1)通过构造进行依赖注入

package x.y;

public class ThingOne {

	public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
		// ...
	}
}

        xml配置方式

<beans>
	<bean id="beanOne" class="x.y.ThingOne">
		<constructor-arg ref="beanTwo"/>
		<constructor-arg ref="beanThree"/>
	</bean>

	<bean id="beanTwo" class="x.y.ThingTwo"/>

	<bean id="beanThree" class="x.y.ThingThree"/>
</beans>

        在一个Bean只有一个有参构造器时,Spring自动会根据构造器参数的Class类型去容器中找到匹配的Bean进行注入。

        当构造器的参数类型是基本数据类型(int,String),构造器无法匹配Spring容器中的Bean进行注入,需要手动配置构造器参数类型和参数值。

package examples;

public class ExampleBean {

	// Number of years to calculate the Ultimate Answer
	private final int years;

	// The Answer to Life, the Universe, and Everything
	private final String ultimateAnswer;

    //@ConstructorProperties注释可以显式命名构造函数参数名(name)
    @ConstructorProperties({"years", "ultimateAnswer"})
	public ExampleBean(int years, String ultimateAnswer) {
		this.years = years;
		this.ultimateAnswer = ultimateAnswer;
	}
}

        xml中配置构造器的参数类型和参数值。

<bean id="exampleBean" class="examples.ExampleBean">
	<constructor-arg type="int" value="7500000"/>
	<constructor-arg type="java.lang.String" value="42"/>
</bean>

        如果参数类型存在歧义,可以使用index属性指定入参顺序,或者通过name属性指定参数名称

<bean id="exampleBean" class="examples.ExampleBean">
	<constructor-arg type="int" value="7500000"/>
	<constructor-arg type="java.lang.String" value="42"/>
</bean>

或

<bean id="exampleBean" class="examples.ExampleBean">
	<constructor-arg name="years" value="7500000"/>
	<constructor-arg name="ultimateAnswer" value="42"/>
</bean>

(2)通过Setter进行依赖注入

Service service;
……
//set注入
public void setService(Service service) {
    this.service = service;
}

        然后在xml配置文件中为该属性设置值

<bean id="myService" class="cn.crazy.service.MyService">
	<property name="service" ref="service"></property>
</bean>

<bean id="service" class="cn.crazy.service.impl.serviceImpl"></bean>

        当然我们也Beandefinition为该属性设置值。

@Component
public class MyPostProcessor implements BeanFactoryPostProcessor {

    @Autowired
	Service service;

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		GenericBeanDefinition beanDefinition = (GenericBeanDefinition)beanFactory.getBeanDefinition("myService");
		/**
		 * 设置属性值
		 */
		beanDefinition.getPropertyValues().addPropertyValue("service",service);
	}

        在日常开发中,我们更多的是使用Setter进行可选依赖的注入,而不是必须的。如果希望Setter的依赖注入是必须的,可以在Setter上加@Autowired注解。

(3)构造器依赖注入与Setter依赖注入的区别

  • 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现。使用构造器进行依赖注入时,如果依赖不存在,会抛出异常。
  • 可选依赖使用setter注入进行,灵活性强。
  • Spring 团队通常提倡构造函数注入,因为它允许您将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。构造函数注入的组件总是以完全初始化的状态返回给调用代码,所以如果构造器注入的依赖存在循环依赖,会报错。
  • 构造函数注入是在对象创建时就完成了依赖注入,而setter注入可以在对象创建后任何时候完成依赖注入。

        综上所述,构造函数注入和setter注入各有优缺点,开发人员可以根据自己的需求选择最适合的方式。通常情况下,如果依赖对象是不可变的,则应该使用构造函数注入;如果依赖对象是可变的,则应该使用setter注入。

二、Spring自动装配

        关于spring的自动装配,可以参考官方文档:Spring自动装配

 (1)Spring自动装配简介

        我们把 Spring 在 Bean 与 Bean 之间建立依赖关系的行为称为“装配”。Spring自动装配(Spring Autowiring)是一种通过自动连接bean之间的依赖关系来简化Spring应用程序开发的技术。

  •  Spring 的自动装配功能可以让 Spring 容器依据某种规则(自动装配的规则,有五种),为指定的 Bean 从应用的上下文(AppplicationContext 容器)中查找它所依赖的 Bean,并自动建立 Bean 之间的依赖关系。而这一过程是在完全不使用任何 <constructor-arg>和 <property> 元素 ref 属性的情况下进行的。
  • Spring 的自动装配功能能够有效地简化 Spring 应用的 XML 配置,因此在配置数量相当多时采用自动装配降低工作量。
  • Spring 框架式默认不支持自动装配的,要想使用自动装配,则需要对 Spring XML 配置文件中 <bean> 元素的 autowire 属性进行设置。

(2)Spring自动装配方式

        自动装配功能有四种方式。您可以指定每个 bean 的自动装配(<bean autowire="XXX">),从而可以选择要自动装配的那些 bean。下表描述了四种自动装配模式:

装配方式

说明
byName按名称自动装配。
Spring 会根据的 Bean中对象属性的名称,在整个应用的上下文 ApplicationContext(IoC 容器)中查找。若某个 Bean 的 id 或 name 属性值与这个对象属性的名称相同,则获取这个 Bean,并与当前的 Bean建立关联关系。
byType按类型自动装配。
Spring 会根据 Bean的对象属性的类型,在整个应用的上下文 ApplicationContext(IoC 容器)中查找。若某个 Bean 的 class 属性值与这个对象属性的类型相匹配,则获取这个 Bean,并与当前的 Bean 建立关联关系。
constructor与 byType 模式相似,不同之处在与它应用于构造器参数(依赖项),如果在容器中没有找到与构造器参数类型一致的 Bean,那么将抛出异常。
构造器装配方式其实就是根据参数的数据类型,进行 byType 模式的自动装配。
no默认值,表示不使用自动装配,Bean 的依赖关系必须通过 <constructor-arg>和 <property> 元素的 ref 属性来定义。

        使用 byType 或构造函数自动装配方式,可以连接数组和集合类型。在这种情况下,容器中匹配预期类型的所有自动装配候选项都被提供以满足依赖关系。如果预期的key类型是 String,则可以自动连接强类型的 Map 实例。自动连接的 Map 实例的值由所有匹配预期类型的 bean 实例组成,Map 实例的key包含相应的 bean 名称。

        注意:在使用byName和byType做为自动装配方式时,需要提供属性的Set()方法,否则Spring无法完成自动装配。

代码演示

 定义一个Service接口,有两个实现类

public interface Service {

	String print();
}

public class ServiceImpl1 implements Service {
	@Override
	public String print() {
		return ServiceImpl1.class.getName();
	}


}

public class ServiceImpl2 implements Service{
	@Override
	public String print() {
		return ServiceImpl2.class.getName();
	}

}

        现在在LearningService 中定义一个属性,在不手动设置值的情况下,如何利用Spring自动装配进行依赖连接。

public class LearningService {


	Service service;

	
	/**
	 * 自动注入模式需要set方法
	 *
	 */

	public void setService(Service service) {
		this.service = service;
	}

	//get()方法非必须
	public Service getService() {
		return service;
	}

	@Override
	public String toString() {
		return "LeanningService{" +
				"service=" + service.print() +
				'}';
	}
}

(i)通过byName的方式进行依赖连接

<!--指定自动注入方式为byName-->
<!--将service的实现注册到Spring中,但是没有手动设置依赖关系-->
    <bean id="learningService" class="cn.crazy.autowirted.LearningService" autowire="byName">

	</bean>


	<bean id="service" class="cn.crazy.autowirted.ServiceImpl1">

	</bean>
	<bean id="service1" class="cn.crazy.autowirted.ServiceImpl2">

	</bean>

        这样Spring会根据LearningService 的属性的名称(service),找到容器中Bean的id或name与属性名称相匹配,然后将这个Bean注入LearningService中。

        Spring中bean的id或name必须唯一,不然抛出如下异常。

        所以这种方式是无法将一个接口的多个实现或一个类的多个子类映射到一个数组或集合中的,因为一个name只能对应一个Bean。

(ii)通过byType的方式进行依赖连接

<!--LearningService中有Service类型的成员变量,如果自动注入的方式为byType,Spring中如果存在一个以上Service类型的bean,会报错
	[Could not autowire. There is more than one bean of 'Service' type. Beans: service1,service. Properties “service”]
	如果自动注入的方式为byName则没有这种问题-->
	<bean id="learningService" class="cn.crazy.autowirted.LearningService" autowire="byType">

	</bean>



	<bean id="service" class="cn.crazy.autowirted.ServiceImpl1">

	</bean>

	<bean id="service1" class="cn.crazy.autowirted.ServiceImpl2">

	</bean>

        如果我们选择这种方式进行自动装配,当一个属性对应的Type找到超过一个实现类时,会出现如下异常。

        出现这种情况时,我们可以将一个主要实现类作为主要的候选对象,或者将不重要的实现类设置为非主要候选对象。(xml配置文件设置<bean primary="true/false">或添加注解@Primary)

         这种方式是可以将一个接口的多个实现或一个类的多个子类映射到一个数组或集合中。

public class LearningService {

	Service service;

	Map<String,Service> serviceMap;

	List<Service> serviceList;

	public List<Service> getServiceList() {
		if(!this.serviceList.isEmpty() && this.serviceList.get(0) != null){
			for (Service service: serviceList) {
				System.out.println(service.print());
			}
		}
		return serviceList;
	}

	public Map<String, Service> getServiceMap() {
		if(!this.serviceMap.isEmpty()){
			Set<Map.Entry<String, Service>> entries = this.serviceMap.entrySet();
			for (Map.Entry<String, Service> service : entries) {
				System.out.println("serviceName : " + service.getKey() + ", serviceImpl : " + service.getValue());
			}
		}
		return serviceMap;
	}

	public void setServiceMap(Map<String, Service> serviceMap) {
		this.serviceMap = serviceMap;
	}

	public void setServiceList(List<Service> serviceList) {
		this.serviceList = serviceList;
	}


	/**
	 * 自动注入模式需要set方法
	 *
	 */

	public void setService(Service service) {
		this.service = service;
	}

	//get()方法非必须
	public Service getService() {
		return service;
	}

	@Override
	public String toString() {
		return "LeanningService{" +
				"service=" + service.print() +
				'}';
	}
}

(iii)通过构造器的方式进行依赖连接

        在只要一个依赖的时候,如果提供了一个接口的多个实现,不同于byType,构造器自动装配方式下不会报错。

<bean id="learningService" class="cn.crazy.autowirted.LearningService" autowire="constructor">

	</bean>
	<bean id="service" class="cn.crazy.autowirted.ServiceImpl1">

	</bean>

	<bean id="service1" class="cn.crazy.autowirted.ServiceImpl2">
public LearningService(Service service) {
		this.service = service;
		System.out.println(" service + " + service.print());
	}

        这种情况下,构造器注入的实现类ServiceImpl1 。如果我们希望注入ServiceImpl2,可以设置primary属性值或加@Primary实现。

        有且仅有一个有参构造器的时候,Spring没有选择,只能选择唯一的那个构造器。那有多个有参构造器的时候,Spring会怎样抉择?

推断构造器

        关于使用构造器自动装配的方式下进行依赖注入时,Spring如何选择构造器?Spring有一套自己的规则,但首先排除构造器参数中带有基本数据类型(String,Int等)的构造器,因为基本数据类型不能作为Spring中的Bean。

        关于构造器的推断,后续章节详细讲。Spring中用一个差异值来对比各个构造器的匹配程度,选出一个Spring认为最优的构造器。在修饰符相同的情况下,Spring会选择参数个数(不包括基本数据类型)最多的那个构造器,可能Spring认为这样可以发挥自动装配的最大作用。如果在构造参数个数相同时,构造器参数的优先级大概为:单个类 > List > Map>Set。

public class LearningService {

	private String name;

	private Service service;
	private Service service1;
	private Map<String,Service> serviceMap;
	private List<Service> serviceList;

	private Set<Service> serviceSet;
	

	public LearningService(String name, Service service, Service service1, Map<String, Service> serviceMap, List<Service> serviceList) {
		this.name = name;
		this.service = service;
		this.service1 = service1;
		this.serviceMap = serviceMap;
		this.serviceList = serviceList;
		System.out.println("name, service , service1 serviceList ,serviceMap constructor ");
	}

	public LearningService(Service service, Service service1, Map<String, Service> serviceMap, List<Service> serviceList) {
		this.service = service;
		this.service1 = service1;
		this.serviceMap = serviceMap;
		this.serviceList = serviceList;
		System.out.println("service , service1 serviceList ,serviceMap constructor ");
	}

	public LearningService(Service service, Service service1) {
		this.service = service;
		this.service1 = service1;
		System.out.println("service , service1 constructor ");
		System.out.println("service = " + service.print() + ", service1 = " + service1.print());
	}

	public LearningService(Service service,Service service1, List<Service> serviceList) {
		this.service = service;
		this.service1 = service1;
		this.serviceList = serviceList;
		System.out.println("service , service1 serviceList constructor ");
		System.out.println("service = " + service.print() + ", service1 = " + service1.print());
	}

	public LearningService(Service service,Service service1, Set<Service> serviceSet) {
		this.service = service;
		this.service1 = service1;
		this.serviceSet = serviceSet;
		System.out.println("service , service1 serviceSet constructor ");
		System.out.println("service = " + service.print() + ", service1 = " + service1.print());
	}

	public LearningService(Service service,Service service1, Map<String,Service> serviceMap) {
		this.service = service;
		this.service1 = service1;
		this.serviceMap = serviceMap;
		System.out.println("service , service1 serviceMap constructor ");
		System.out.println("service = " + service.print() + ", service1 = " + service1.print());
	}

	public LearningService(Service service) {
		this.service = service;
		System.out.println("service constructor ");
	}

	public LearningService(List<Service> serviceList) {
		this.serviceList = serviceList;
		System.out.println("serviceList constructor ");
	}

	public LearningService(Map<String,Service> serviceMap) {
		this.serviceMap = serviceMap;
		System.out.println("serviceMap constructor ");
	}

	
}

        这里会打印"service , service1 serviceList ,serviceMap constructor "。

(3)修改自动状态的方式

        除了在xml中配置default-autowire或autowire属性值外,还可以通过BeanDefinition设置自动装配的方式。

/**
* *AUTOWIRE_NO  0
* AUTOWIRE_BY_NAME  1 
* AUTOWIRE_BY_TYPE  2
* AUTOWIRE_CONSTRUCTOR  3
**/
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);

        可以在创建BeanDefinition对象时指定自动装配的值,也可以通过BeanFactoryPostProcessor后置处理器修改这个值。

三、@Autowired和@Resource进行依赖注入

        很多人会把@Autowired和@Resource进行依赖注入也称为自动装配,其实这是不正确的,@Autowired和@Resource进行依赖注入不属于自动装配,通过beanDefinition.getAutowireMode()可以发现加了这两个注解的类的值为AUTOWIRE_NO。

        而且在日常的项目中,我们更多的是使用注解的方式进行Spring开发,xml配置的方式会相对少一些,所以使用@Autowired或Resource进行依赖注入更为频繁。

@Autowired和@Resource二者的区别

        1)来源不同:@Autowired 来自 Spring 框架,而 @Resource 来自于(Java)JSR-250;

        2)依赖查找的顺序不同:@Autowired 先根据类型再根据名称查询,而 @Resource 先根据名称再根据类型查询;

        3)支持的参数不同:@Autowired 只支持设置 1 个参数,而 @Resource 支持设置 7 个参数;

        4)依赖注入的用法支持不同:@Autowired 既支持构造方法注入,又支持属性注入和 Setter 注入,而 @Resource 只支持属性注入和 Setter 注入;

        5)处理注解的后置处理器不同。处理@Resource注解依赖注入的后置处理器是CommonAnnotationBeanPostProcessor,而处理@Autowired注解依赖注入的是 AutowiredAnnotationBeanPostProcessor

  • @Autowired查找顺序

  • @Resource查找顺序

四、源码分析

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		……

		//MutablePropertyValues propertyValues = mbd.getPropertyValues();
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

	
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			//底层是List<PropertyValues>.add(pvs);
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			/**
			 * @see org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry registry,Object source)
			 */
			//调用第六次后置处理器
			//这里的BeanPostProcessor是由spring启动时自己注入的,这里使用了策略模式,
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

		if (pvs != null) {
			//应用PropertyValues,将pvs应用于bw中
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

(1)byType源码分析

        byName和byType的处理逻辑类似,我们选择代码相对复杂的byType源码进行分析。

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);
		//代码块一:返回有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 = !(bw.getWrappedInstance() instanceof PriorityOrdered);
					//获取通过byType自动注入依赖项的描述符
					DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
					//代码块二:解析自动注入的属性值
					Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
					if (autowiredArgument != null) {
                        //代码块九:将解析出来属性名对应的属性值添加到MutablePropertyValues
						pvs.add(propertyName, autowiredArgument);
					}

					//autowiredBeanNames有多个值表示属性类型是数组或集合元素
					for (String autowiredBeanName : autowiredBeanNames) {
						//这个是往dependentBeanMap中加入一个autowiredBeanName为key,Set<String> dependentBeans为value(beanName添加到Set中)
						//dependentBeanMap就是维护了一个autowiredBeanName(key)需要被注入到哪些bean(set)的map集合
						//同时也会这往dependenciesForBeanMap中加入一个beanName为key,Set<String> dependenciesForBean为value(autowiredBeanName添加到Set中)
						//dependenciesForBeanMap就是维护了一个beanName(key)需要注入哪些bean(set)的map集合
                        //代码块十:维护依赖关系对应的集合
						registerDependentBean(autowiredBeanName, beanName);
						if (logger.isTraceEnabled()) {
							logger.trace("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);
			}
		}
	}

   (i)代码块一:unsatisfiedNonSimpleProperties(),返回有set()方法的属性的名字数组。

        这个方法是利用Java内省机制返回beanClass中有set()方法的属性名数组。byName也是通过这个方法找到要进行依赖注入的属性名数组,这也是byTye和byName必须提供属性的set()方法的原因。

protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
		Set<String> result = new TreeSet<>();
		PropertyValues pvs = mbd.getPropertyValues();
		//所有的属性描述器,Java内省机制
		PropertyDescriptor[] pds = bw.getPropertyDescriptors();
		for (PropertyDescriptor pd : pds) {
			//pd.getWriteMethod()就是setXX()方法,pd.getReadMethod()就是getXX()方法
			if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
					!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
				result.add(pd.getName());
			}
		}
		return StringUtils.toStringArray(result);
	}

        我们知道Java内省获取属性描述器的一般方式需要借助Introspector类,那为什么Spring可以直接通过bw.getPropertyDescriptors()拿到beanClass的属性描述器?

//通过Java获取属性描述器的一般方式
BeanInfo beanInfo = Introspector.getBeanInfo(XXX.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();


……

         带着这个疑问?我大概看了一下spring源码,因为这块代码也不是今天的重点,大概说一下是怎样实现的。就是在属性填充之前,肯定要先创建实例,spring会在推断合适的构造器用于创建实例,而创建出来的实例beanClass会用BeanWrapper封装

//根据推断出来的构造器及其参数创建bean实例,并封装到bw对象中
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));

……
public void setBeanInstance(Object object) {
		this.wrappedObject = object;
		this.rootObject = object;
		this.typeConverterDelegate = new TypeConverterDelegate(this, this.wrappedObject);
		setIntrospectionClass(object.getClass());
	}

protected void setIntrospectionClass(Class<?> clazz) {
		if (this.cachedIntrospectionResults != null && this.cachedIntrospectionResults.getBeanClass() != clazz) {
			this.cachedIntrospectionResults = null;
		}
	}

        最后CachedIntrospectionResults(Class<?> beanClass) 的beanClass就是构造器创建的bean实例,也是BeanWrapperImpl的this.wrappedObject的值。

public interface BeanWrapper extends ConfigurablePropertyAccessor {
……

PropertyDescriptor[] getPropertyDescriptors();


}


public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper {



private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
		try {
			if (logger.isTraceEnabled()) {
				logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]");
			}
            //Java内省机制
			this.beanInfo = getBeanInfo(beanClass);

			if (logger.isTraceEnabled()) {
				logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
			}
			this.propertyDescriptors = new LinkedHashMap<>();

			Set<String> readMethodNames = new HashSet<>();

			// beanClass对应的属性描述器
			PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor pd : pds) {
				if (Class.class == beanClass &&
						("classLoader".equals(pd.getName()) ||  "protectionDomain".equals(pd.getName()))) {
					// Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
					continue;
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Found bean property '" + pd.getName() + "'" +
							(pd.getPropertyType() != null ? " of type [" + pd.getPropertyType().getName() + "]" : "") +
							(pd.getPropertyEditorClass() != null ?
									"; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
				}
				pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
				this.propertyDescriptors.put(pd.getName(), pd);
				Method readMethod = pd.getReadMethod();
				if (readMethod != null) {
					readMethodNames.add(readMethod.getName());
				}
			}

			// Explicitly check implemented interfaces for setter/getter methods as well,
			// in particular for Java 8 default methods...
			Class<?> currClass = beanClass;
			while (currClass != null && currClass != Object.class) {
				introspectInterfaces(beanClass, currClass, readMethodNames);
				currClass = currClass.getSuperclass();
			}

			// Check for record-style accessors without prefix: e.g. "lastName()"
			// - accessor method directly referring to instance field of same name
			// - same convention for component accessors of Java 15 record classes
			introspectPlainAccessors(beanClass, readMethodNames);

			this.typeDescriptorCache = new ConcurrentReferenceHashMap<>();
		}
		catch (IntrospectionException ex) {
			throw new FatalBeanException("Failed to obtain BeanInfo for class [" + beanClass.getName() + "]", ex);
		}
	}


(ii)代码块二/代码块三 :resolveDependency(),解析自动注入的属性值,真正解析属性依赖的方法doResolveDependency()。

         @Autowired进行依赖注入也会进行使用到这个方法来解析依赖。resolveMultipleBeans()方法里面也是通过findAutowireCandidates()找到对应的实现类的,不过它会对结果(个数>1)进行排序。

        这个方法大致总结为:

        1)根据属性的type到spring容器中找到该类型的所有实现类,并封装到matchingBeans中,其中key为属性值,value为属性值对应的实例对象或Class对象。

        2)如果找到多于一个实现,推断最终自动装配的属性名,会根据beanClass是否设置了Primary和Priority属性值进行推断,在byType方式下,如果没有设置Primary和Priority属性值,推断出的结果为null,且会抛出异常

        3)根据推断出来的属性名,到matchingBeans找到对应的value,如果value是Class,到spring容器中获取对应的bean并返回。

@Override
	@Nullable
	public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		
	……
			//如果加了@Lazy注解,产生一个代理对象
			//思考:这个代理对象的作用是什么?
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
                // 代码块三 :真正解析属性依赖的方法
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		……
	}

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			//shortcut可以理解为一个快照,如果提供了一个快照,直接返回这个快照,不要执行后面繁杂的流程
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}
			//field的类型,这也是Java内省机制
			Class<?> type = descriptor.getDependencyType();
			//是否有默认值
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			
            ……

			//这里是实现集合类型的属性注入,如果加了@Order(value = xxx)或实现了PriorityOrdered接口,返回的结合会是有序的结果
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}
			//代码块四:找非集合类型属性匹配的bean
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;
			//根据type类型找到有多个实现(多态)
			if (matchingBeans.size() > 1) {
				//代码块七:推断具体注入的beanName,如果是byType注入多个相同类型的,且没有primary和priority处理,这里返回null
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						//@Autowired(required = "ture")表示必须注入,如果无法推断注入的值,抛出异常
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {
						// In case of an optional Collection/Map, silently ignore a non-unique case:
						// possibly it was meant to be an empty collection of multiple regular beans
						// (before 4.3 in particular when we didn't even look for collection beans).
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
				// We have exactly one match.
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
            //代码块八:从容器获取候选实例对象
			if (instanceCandidate instanceof Class) {
				//如果是Class类型,通过beanFactory.getBean(autowiredBeanName)
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

(iii)代码块四:findAutowireCandidates(),找到非集合类型属性匹配的bean。

        这个方法大概可以总结为:

        1)根据requiredType类型找到容器中其所有实现类的beanName(如果存在父容器,也会到父容器中找),本质是遍历beanDefinitionNames,找到其中所有requiredType类型的bean对应的名字。同时创建一个Map集合用于存放最终找到的候选对象(result)。

        2)遍历this.resolvableDependencies是否有与requiredType匹配的bean,如果有直接从中获取对应的值,并添加到result候选对象map中。(this.resolvableDependencies存放的是spring在beanFactory准备阶段put的元素)

        3)遍历找到的候选对象名称,判断是否自身引用和对应的bean定义是否有资格作为自动候选对象,将符合条件的候选对象对应的实例对象或Class对象加入result集合中。

protected Map<String, Object> findAutowireCandidates(
			@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {

		//通过type(Class)在spring容器中找到对应的type的所有实现类的beanName(如果存在父容器,也会到父容器中找)
		// 这个方法的本质是遍历beanDefinitionNames,找到其中所有requiredType类型的beanName
		String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this, requiredType, true, descriptor.isEager());
		Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
		//this.resolvableDependencies在beanFactory准备阶段会put一些元素
		//看this.resolvableDependencies是否有与requiredType匹配的,如果有直接从中获取对应的值
		for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
			Class<?> autowiringType = classObjectEntry.getKey();
			if (autowiringType.isAssignableFrom(requiredType)) {
				Object autowiringValue = classObjectEntry.getValue();
				autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
				if (requiredType.isInstance(autowiringValue)) {
					result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
					break;
				}
			}
		}
		for (String candidate : candidateNames) {
			//isSelfReference见名知意,自身引用(candidate==beanName)
			//将beanName对应的Class返回(创建)
            // 代码五:isAutowireCandidate
			if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
                //代码块六:将符合条件的candidate对应的实例对象或Class对象加入result集合中
				addCandidateEntry(result, candidate, descriptor, requiredType);
			}
		}
		if (result.isEmpty()) {
			boolean multiple = indicatesMultipleBeans(requiredType);
			// Consider fallback matches if the first pass failed to find anything...
			DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
			for (String candidate : candidateNames) {
				if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
						(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
					addCandidateEntry(result, candidate, descriptor, requiredType);
				}
			}
			if (result.isEmpty() && !multiple) {
				// Consider self references as a final pass...
				// but in the case of a dependency collection, not the very same bean itself.
				for (String candidate : candidateNames) {
					if (isSelfReference(beanName, candidate) &&
							(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
							isAutowireCandidate(candidate, fallbackDescriptor)) {
						addCandidateEntry(result, candidate, descriptor, requiredType);
					}
				}
			}
		}
		return result;
	}

 (iv)代码五:isAutowireCandidate(),确定指定的bean定义是否有资格作为自动候选对象被注入到声明了匹配类型依赖的其他bean中。

        这里一般会根据查找出来的candidateBean对应的beanDefinition构建BeanDefinitionHolder对象,一般这个方法都会返回true,因为beanDefinition.isAutowireCandidate()默认true,除非程序员配置了值(autowire-candidate="false",把这个可以注入到其他对象的资格给关闭了)。

/**
	 * 确定指定的bean定义是否有资格作为自动候选对象被注入到声明了匹配类型依赖的其他bean中。
	 */
	protected boolean isAutowireCandidate(
			String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver)
			throws NoSuchBeanDefinitionException {

		String bdName = BeanFactoryUtils.transformedBeanName(beanName);
		//BeanDefinitionMap容器中是否存在这个bean
		if (containsBeanDefinition(bdName)) {
			return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(bdName), descriptor, resolver);
		}
		//singletonObjects容器(单例池)中是否存在这个bean
		else if (containsSingleton(beanName)) {
			return isAutowireCandidate(beanName, new RootBeanDefinition(getType(beanName)), descriptor, resolver);
		}

		//如果当前容器中没找,到父容器中找
		BeanFactory parent = getParentBeanFactory();
		if (parent instanceof DefaultListableBeanFactory) {
			// No bean definition found in this factory -> delegate to parent.
			return ((DefaultListableBeanFactory) parent).isAutowireCandidate(beanName, descriptor, resolver);
		}
		else if (parent instanceof ConfigurableListableBeanFactory) {
			// If no DefaultListableBeanFactory, can't pass the resolver along.
			return ((ConfigurableListableBeanFactory) parent).isAutowireCandidate(beanName, descriptor);
		}
		else {
			return true;
		}
	}


protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd,
			DependencyDescriptor descriptor, AutowireCandidateResolver resolver) {

		String bdName = BeanFactoryUtils.transformedBeanName(beanName);
		//设置对应BD里面的beanClass值,如果BeanDefinition的beanClass值为空,通过mbd.getBeanClassName()初始化加载对应的Class到beanClass属性中
		// 这个方法基本没有用到bdName这个参数
		resolveBeanClass(mbd, bdName);
		if (mbd.isFactoryMethodUnique && mbd.factoryMethodToIntrospect == null) {
			new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
		}
		BeanDefinitionHolder holder = (beanName.equals(bdName) ?
				this.mergedBeanDefinitionHolders.computeIfAbsent(beanName,
						key -> new BeanDefinitionHolder(mbd, beanName, getAliases(bdName))) :
				new BeanDefinitionHolder(mbd, beanName, getAliases(bdName)));
		//private boolean autowireCandidate = true;
		return resolver.isAutowireCandidate(holder, descriptor);
	}

(v)代码块六: addCandidateEntry(),将符合条件的candidate对应的实例对象或Class对象加入result集合中。

private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
			DependencyDescriptor descriptor, Class<?> requiredType) {

		if (descriptor instanceof MultiElementDescriptor) {
			Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
			if (!(beanInstance instanceof NullBean)) {
				candidates.put(candidateName, beanInstance);
			}
		}
		else if (containsSingleton(candidateName) || (descriptor instanceof StreamDependencyDescriptor &&
				((StreamDependencyDescriptor) descriptor).isOrdered())) {
			//如果spring容器中存在candidateName,通过getBean()返回对应的beanInstance
			//为什么会存在?可能其他bean的属性也包含这个candidateName,那个bean已经完成初始化了,candidateName对应的bean被创建了
			Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
			candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
		}
		else {
			//getType(candidateName)返回bd对应的实现类对应的Class(不是接口的Class)
			candidates.put(candidateName, getType(candidateName));
		}
	}

(vi)代码块七:determineAutowireCandidate(),推断具体注入的beanName。

        如果是byType注入多个相同类型的实现,且没有进行primary和priority处理,这里返回null。

@Nullable
	protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
		Class<?> requiredType = descriptor.getDependencyType();
		//如果candidates中的某个bean为primary[<bean primary="true"/>或@Primary],直接返回这个beanname
		String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
		if (primaryCandidate != null) {
			return primaryCandidate;
		}
		//如果指定了优先级,返回优先级最高的beanname[只对@Priority(value = xx)有效,对@Order(value = xxx)或实现了PriorityOrdered接口无效优先级(集合元素排序)]
		String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
		if (priorityCandidate != null) {
			return priorityCandidate;
		}
		// Fallback
		for (Map.Entry<String, Object> entry : candidates.entrySet()) {
			String candidateName = entry.getKey();
			Object beanInstance = entry.getValue();
			//matchesBeanName主要判断candidateName(包括别名)与descriptor.getDependencyName()是否匹配
			//this.resolvableDependencies.containsValue(beanInstance)如果当前依赖关联里有beanInstance,直接返回对应的candidateName
			//当自动装配方式为byType时,descriptor.getDependencyName()为null
			//当使用@Autowired进行依赖注入时descriptor.getDependencyName()为属性名称
			//这也是@Autowired如果根据type找到多个实现,就会再从这几个实现里找到name与属性名称匹配的candidateName
			if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
					matchesBeanName(candidateName, descriptor.getDependencyName())) {
				return candidateName;
			}
		}
		return null;
	}

(vii)代码八:resolveCandidate(),从容器中获取候选实例。

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
			throws BeansException {

		return beanFactory.getBean(beanName);
	}

(viii)代码块九:将解析出来属性名对应的属性值添加到MutablePropertyValues。

        bd对象有propertyValues属性,用于存放beanClass的所有的属性的属性名称和属性值。自动装配的本质就是解析出属性名对应的bean,并放入添加到MutablePropertyValues中,最后封装到BeanWrapperImpl的propertyValues属性中。

public MutablePropertyValues add(String propertyName, @Nullable Object propertyValue) {
		addPropertyValue(new PropertyValue(propertyName, propertyValue));
		return this;
	}

 (ix)代码块十:registerDependentBean(),维护依赖关系对应的集合。

        dependentBeanMap就是维护了一个autowiredBeanName(key)需要被注入到哪些bean(set)的map集合
        dependenciesForBeanMap就是维护了一个beanName(key)需要注入哪些bean(set)的map集合

public void registerDependentBean(String beanName, String dependentBeanName) {
		String canonicalName = canonicalName(beanName);

		synchronized (this.dependentBeanMap) {
			Set<String> dependentBeans =
					this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
			if (!dependentBeans.add(dependentBeanName)) {
				return;
			}
		}

		synchronized (this.dependenciesForBeanMap) {
			Set<String> dependenciesForBean =
					this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
			dependenciesForBean.add(canonicalName);
		}
	}


                   
    (x)代码块十一:convertForProperty(),属性转换

        为什么说byName或byType的依赖注入是基于内省实现的?

        applyPropertyValues(beanName, mbd, bw, pvs)属性值应用的代码中最后找到将属性名转换为bw中对象属性值的方法convertForProperty()。

public Object convertForProperty(@Nullable Object value, String propertyName) throws TypeMismatchException {
		CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
		PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
		if (pd == null) {
			throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
					"No property '" + propertyName + "' found");
		}
		TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
		if (td == null) {
			td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
		}
		return convertForProperty(propertyName, null, value, td);
	}

(2)@Autowired依赖注入源码分析

        为什么说@Autowired和@Resource依赖注入不属于自动装配?

        除了@Autowired和@Resource对应的AutowireMode为no,同时byName和byType是通过Java自省机制实现的,而@Autowired和@Resource依赖注入是基于Java反射实现的。

        注:@Autowired和@Resource依赖注入的代码逻辑基本相同,这是解析注解稍有差别,这里就只针对@Autowired源码进行分析。

(i)AutowiredAnnotationBeanPostProcessor,解析@Autowired注解依赖注入的后置处理器

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		……

			/**
			 * @see org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry registry,Object source)
			 */
			//调用第六次后置处理器
			//这里的BeanPostProcessor是由spring启动时自己注入的,这里使用了策略模式,
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
                // 通过AutowiredAnnotationBeanPostProcessor完成@Autowired注解注入的解析
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
		……

		if (pvs != null) {
			//应用PropertyValues,将pvs应用于bw中
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

(ii)postProcessProperties(),在工厂应用给定的属性值之前把它们注入到
指定的bean中

//属性注入
	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		//this.injectionMetadataCache.get(cacheKey)中获取值,在第三次调用后置处理器时(合并bd),就已经找出所有需要注入点
        // 代码块一:找到通过@Autowired注入的属性元数据信息
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
            //代码块五:属性注入
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

(ii)代码块一:findAutowiringMetadata(),找到通过@Autowired注入的对象(Field和Method)的元数据信息

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quick check on the concurrent map first, with minimal locking.
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		// 是否需要刷新缓存,如果metadata == null或缓存的class与当前的clazz不相同,表示要刷新
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					//代码块二:构造自动注入的元数据
					metadata = buildAutowiringMetadata(clazz);
					//添加缓存
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

 (ii)代码块二:buildAutowiringMetadata(),构造自动注入的元数据对象

        这个方法大致总结为:

        1)遍历targetClass的所有field,如果field上添加了@Autowired注解,判断是否为static类型,如果是,退出遍历。如果不是,获取require属性值,并根据field对象和require属性值构建AutowiredFieldElement对象。

        2)遍历targetClass的所有method,如果方法是桥接方法,判断其是否“可见”的桥接方法。如果不是,退出遍历。如果method上添加了@Autowired注解,判断是否为static类型,如果是,退出遍历。如果不是,获取require属性值,并根据field对象和require属性值构建AutowiredFieldElement对象。

        3)将fiel和method对应的AutowiredFieldElement添加到elements集合,并通过elements和Class构建InjectionMetadata对象。

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

			//代码块三:处理field上的@Autowired
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				// 将属性域上@Autowired的注解信息
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
				if (ann != null) {
					// @Autowired不支持静态属性域的依赖注入
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					// 获取@Autowired中required的值
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

			//代码块四:处理method上的@Autowired
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				//比较桥接方法和它所桥接的方法的签名。如果参数和返回类型是相同的,这是一个“可见”桥接方法
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (Modifier.isStatic(method.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					if (method.getParameterCount() == 0) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation should only be used on methods with parameters: " +
									method);
						}
					}
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});

			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return InjectionMetadata.forElements(elements, clazz);
	}

(iii)代码块三:doWithLocalFields(),处理field上的@Autowired,将符合要求的field构建成AutowiredFieldElement对象。

public static void doWithLocalFields(Class<?> clazz, FieldCallback fc) {
		for (Field field : getDeclaredFields(clazz)) {
			try {
				fc.doWith(field);
			}
			catch (IllegalAccessException ex) {
				throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
			}
		}
	}

(iv)代码块四:doWithLocalMethods(),处理method上的@Autowired,将符合要求的method构建成AutowiredFieldElement对象。

public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
		Method[] methods = getDeclaredMethods(clazz, false);
		for (Method method : methods) {
			try {
				mc.doWith(method);
			}
			catch (IllegalAccessException ex) {
				throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
			}
		}
	}

(v)创建AutowiredFieldElement对象,Field类型和Method类型的AutowiredFieldElement对象区别在于属性isField的值不同。

public AutowiredFieldElement(Field field, boolean required) {
			super(field, null);
			this.required = required;
		}


public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {
			super(method, pd);
			this.required = required;
		}


protected InjectedElement(Member member, @Nullable PropertyDescriptor pd) {
			this.member = member;
            // 是域还是方法
			this.isField = (member instanceof Field);
			this.pd = pd;
		}

// Field和Method都是Member的实现

public final
class Field extends AccessibleObject implements Member {
……
}

public final class Method extends Executable {
}

public abstract class Executable extends AccessibleObject
    implements Member, GenericDeclaration {

}

(iv)代码块五:inject(),属性注入

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			for (InjectedElement element : elementsToIterate) {
				if (logger.isTraceEnabled()) {
					logger.trace("Processing injected element of bean '" + beanName + "': " + element);
				}
				//element 分为FieldElement和MethodElement
				element.inject(target, beanName, pvs);
			}
		}
	}
        a.Field类型的AutowiredFieldElement的注入

        这个方法中有很多我们在byType中已经分析过的方法,resolveDependency()、registerDependentBeans(),通过Field获取属性描述器,根据field的Class类型去容器中找对应的实现类,如果resolveDependency()在field中找到多个(matchingBeans),不同于byType的是,当使用@Autowired进行依赖注入时descriptor.getDependencyName()为属性名称(field.getName()),matchingBeans.get(fieldName)返回符合规则的候选实例。推断出候选对象后维护依赖关系对应的集合。

        这个方法还会创建缓存,不过是在只推断出一个候选对象的时候才会有缓存。而且这里缓存的只是属性的描述器desc和推断出来的autowiredBeanName,并没有将推断出来的候选对象实例加入缓存,这就意味着即使有缓存,还是要再执行esolveDependency()才能推断出最后注入的候选对象,只是缓存了某些中间变量的设置。

//Field属性注入
		// AutowiredFieldElement.inject()
		@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			//cached的作用是什么
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			else {
				DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
				desc.setContainingClass(bean.getClass());
				Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
				Assert.state(beanFactory != null, "No BeanFactory available");
				TypeConverter typeConverter = beanFactory.getTypeConverter();
				try {
					//核心方法
					/**
					 * desc是这个field的信息,beanName为field对应的name
					 */
					value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
				}
				synchronized (this) {
					if (!this.cached) {
						if (value != null || this.required) {
							this.cachedFieldValue = desc;
							//维护依赖关系
							registerDependentBeans(beanName, autowiredBeanNames);
							//只找到唯一的实现,如果是数组类型或集合类型,且找到多个实现,不会进行缓存
							if (autowiredBeanNames.size() == 1) {
								String autowiredBeanName = autowiredBeanNames.iterator().next();
								if (beanFactory.containsBean(autowiredBeanName) &&
										beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
									//设置缓存
									// 这里缓存的只是属性的描述器desc和推断出来的autowiredBeanName,并没有将推断出来的候选对象实例加入缓存
									this.cachedFieldValue = new ShortcutDependencyDescriptor(
											desc, autowiredBeanName, field.getType());
								}
							}
						}
						else {
							this.cachedFieldValue = null;
						}
						this.cached = true;
					}
				}
			}
			//通过反射设置属性值
			if (value != null) {
				// 设置访问权限field.setAccessible(true);
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}
	}
         b.Method类型的AutowiredFieldElement的注入。

        与Field类型的AutowiredFieldElement的注入逻辑类似。

// AutowiredMethodElement.inject()
		@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			if (checkPropertySkipping(pvs)) {
				return;
			}
			Method method = (Method) this.member;
			Object[] arguments;
			if (this.cached) {
				// Shortcut for avoiding synchronization...
				arguments = resolveCachedArguments(beanName);
			}
			else {
				int argumentCount = method.getParameterCount();
				arguments = new Object[argumentCount];
				DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
				Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
				Assert.state(beanFactory != null, "No BeanFactory available");
				TypeConverter typeConverter = beanFactory.getTypeConverter();
				for (int i = 0; i < arguments.length; i++) {
					MethodParameter methodParam = new MethodParameter(method, i);
					// 当前被注入的特定依赖项的描述符
					DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
					currDesc.setContainingClass(bean.getClass());
					descriptors[i] = currDesc;
					try {
						/**
						 * 解析出注入的属性值,byType源码部分已经分析了这个方法
						 *@see org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, java.lang.String, java.util.Set, org.springframework.beans.TypeConverter)
 						 */

						Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
						if (arg == null && !this.required) {
							arguments = null;
							break;
						}
						arguments[i] = arg;
					}
					catch (BeansException ex) {
						throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
					}
				}
				synchronized (this) {
					if (!this.cached) {
						if (arguments != null) {
							DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
							// 维护依赖关系集合,byType源码部分已经分析了这个方法
							registerDependentBeans(beanName, autowiredBeans);
							// 返回的候选beanName的大小与方法参数个数一致
							// 如果方法参数是数组或集合类型且找到多个实现,不会进入这个方法
							if (autowiredBeans.size() == argumentCount) {
								Iterator<String> it = autowiredBeans.iterator();
								Class<?>[] paramTypes = method.getParameterTypes();
								for (int i = 0; i < paramTypes.length; i++) {
									String autowiredBeanName = it.next();
									// beanName对应的bean实例的类型是否与paramTypes类型一致
									if (beanFactory.containsBean(autowiredBeanName) &&
											beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
										// 放入缓存快照
										// 这里缓存的只是属性的描述器desc和推断出来的autowiredBeanName,并没有将推断出来的候选对象实例加入缓存
										// 所以拿到缓存后还需要执行resolveDependency()推断出最终注入的候选实例对象
										cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
												descriptors[i], autowiredBeanName, paramTypes[i]);
									}
								}
							}
							this.cachedMethodArguments = cachedMethodArguments;
						}
						else {
							this.cachedMethodArguments = null;
						}
						// 设置缓存标识为true
						this.cached = true;
					}
				}
			}
			if (arguments != null) {
				try {
					// 设置访问权限
					ReflectionUtils.makeAccessible(method);
					// 反射执行方法
					method.invoke(bean, arguments);
				}
				catch (InvocationTargetException ex) {
					throw ex.getTargetException();
				}
			}
		}

        不同于byType,属性注入方法 inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)中的参数pvs在Field类型和Method类型的注入中都没有用到。@Autowired依赖注入是通过Java反射(field.set(bean, value)/method.invoke(bean, arguments))实现的。

五、总结

         Spring中的自动装配确实帮我们简化了一些属性的配置,但是对于简单类型,如String、int等基本数据类型,是无法使用自动装配的。同时在存在多个存在歧义的对象时,自动装配会返回不确定的结果,甚至会抛出异常。日常开发中,我们更多的是使用 @Autowired注解(或@Resource注解)进行依赖注入,这种方式即实现了自动装配的灵活性,也兼顾了手动装配的可预知性。

        通过阅读源码发现:@Autowired注解(或@Resource注解)依赖注入是通过Java反射(field.set(bean, value)/method.invoke(bean, arguments))实现的,byName和byType是将推断出来的属性名称和属性对象添加到PropertyValues中,后续在封装BeanWrapper对象时通过Java内省机制完成属性注入的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1089132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

注意力屏蔽(Attention Masking)在Transformer中的作用 【gpt学习记录】

填充遮挡&#xff08;Padding Masking&#xff09;&#xff1a; 未来遮挡&#xff08;Future Masking&#xff09;&#xff1a;

近地面无人机植被定量遥感与生理参数反演

目录 专题一 近十年近地面无人机植被遥感文献分析、传感器选择、观测方式及质量控制要点 专题二 辐射度量与地物反射特性 专题三 无人机遥感影像辐射与几何处理 专题四 光在植被叶片与冠层中的辐射传输机理及平面模型应用 专题五 植被覆盖度与叶面积指数遥感估算 更多应用…

sylar高性能服务器-日志(P7-P8)代码解析

文章目录 p71.TabFormatItem2.init函数&#xff0c;对于{}内容的解析3.Util.h4.CmakeLists5.优化日志输出-流式输出 p81.优化日志输出-格式化输出2.日志管理器3.单例模型设计 测试(无调试步骤) P7P8两节视频新增内容不多&#xff0c;主要看下优化日志输出使用的宏函数。本次记录…

python获取网口列表(获取网络接口列表、网口表)socket.if_nameindex()

文章目录 获取网口列表测试 获取网口列表 以下python代码将打印系统中所有存在的网络接口列表&#xff1a; import socketdef print_interfaces_list():# 打印所有的网络接口列表available_interfaces socket.if_nameindex()# 转换成字典形式 {if_index: if_name}available_…

6个视频剪辑必备的素材网站,免费下载。

视频剪辑必备的视频资源、音效素材、BGM&#xff0c;这6个网站全部免费下载&#xff0c;赶紧收藏起来吧&#xff01; 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYxMjky 菜鸟图库网素材非常丰富&#xff0c;网站主要还是以设计类素材为主&#xff0c;高清视频素材…

TSINGSEE青犀智慧广场智能监控解决方案,助力广场监控数字化转型

前期和大家说过世界最大的城市公园——合肥市骆岗公园的监控方案&#xff0c;大家都很感兴趣&#xff0c;后台还有粉丝留言想看看广场类场景的智能方案&#xff0c;今天小编就和大家聊一聊。 广场视频监控方案大体和公园场景类似&#xff0c;但由于广场比公园更加空旷&#xf…

centos 里面的service自启动app.jar,出现两个java进程,app是同一个端口

当使用jps -lv查看java虚拟机进程 app.jar启动后&#xff0c;居然出现两个启动进程&#xff0c;而且他们的端口都一样&#xff0c;同一端口&#xff0c;是不允许启动两个相同app的。 使用进程ps查看进程工具 #ps -aux 参数说明&#xff1a; a: 显示跟当前终端关联的所有进…

到2026年,超过80%企业将使用生成式AI

10月12日&#xff0c;全球著名信息咨询调查机构Gartner在官网&#xff0c;公布了一项调查数据&#xff0c;到2026年&#xff0c;超过80%的企业将使用生成式AI API&#xff0c;或部署生成式AI的应用程序。而2023年这一比例还不到5%。 Gartner副总裁兼高级分析师 Arun Chandrase…

【约束布局】ConstraintLayout配合Guideline解决两个子控件其中一个被挤出屏幕的问题

一、需求 屏幕横向显示文本框A和图标B&#xff0c;A在B的左侧&#xff0c;B紧贴在A的右边显示&#xff0c;文本框A的字数不确定&#xff0c;文本框A的字数足够多时&#xff0c;换行显示&#xff0c;并且保证图标B一直在文本框A的右侧&#xff0c;且不被挤出屏幕。 二、问题 本来…

Java Object转String方式

Map<String,Object> map new HashMap<>(); map.put("a1","a"); map.put("a2",""); map.put("a3",1); map.put("a4",null);一、强制转换 value "a"或""可以进行强制转换String…

众佰诚:新手开抖音小店申请流程是什么

抖音小店为抖音平台上的商家提供了一个全新的销售渠道&#xff0c;让更多创业者能够轻松实现线上销售。如果你是一位希望在抖音上开展电商业务的新手&#xff0c;下面将为你详细介绍如何申请开通抖音小店。 一、准备工作 首先&#xff0c;你需要准备好以下材料&#xff1a; 营业…

数学术语之源——代数——(子空间的)直和(direct sum)

1. 关于(子空间的)直和(direct sum)的较正式定义 令 为向量空间 的子空间,若 且 是独立的&#xff0c;则称 是子空间 的直和(direct sum), 记为 &#xff0c; 这种表示在同一个基的前提下是唯一的。 一个直观几何类比理解(个人愚见)&#xff1a;如果我将向量空间V 看…

计算机基础——内存

文章目录 内存一、内存条、总线、DMA二、内存管理1、为什么要有逻辑地址2、逻辑地址和物理地址如何映射3、分页时间和空间优化4、程序内部的内存管理-分段 三、内存相关的系统调用1、用户态和内核态 四、Java内存 内存 提示&#xff1a;这里可以添加本文要记录的大概内容&…

JS+Jquery用法

1. 当存在多个select时&#xff0c;想要获取每一个select的选中的值(使用变量赋值的方法). var Metric "";$(#Metric).change(function () {Metric $(this).children("option:selected").val();console.log("Metric:" Metric);}); 2. 在页面…

海外代理IP与VPN有何区别?哪个更好?

当谈到网络安全和IP变更时&#xff0c;人们会想到VPN和IP代理服务器。很多人很困惑&#xff0c;它们之间有什么区别&#xff0c;应该选择哪一个呢&#xff1f;这取决于您的需求来决定哪一个更好。 一、什么是VPN与IP代理&#xff1f; VPN 是虚拟专用网络 (Virtual Private Net…

ACP.项目管理.5种复盘会议

复盘要怎么做的有水准&#xff0c;让领导满意&#xff0c;方式方法很重要。今天给你们安利5种复盘方法&#xff0c;保准你省事&#xff0c;领导还满意。 一、KPT复盘法 7月份年中一直在做和复盘相关的事&#xff0c;像公司的OKR复盘、年中战略规划&#xff0c;不过日常很多生…

Hadoop 安装教程 (Mac m1/m2版)

安装JDK1.8 这里最好是安装1.8版本的jdk 1. 进入官网Java Downloads | Oracle Hong Kong SAR, PRC,下滑到中间区域找到JDK8 2.选择mac os,下载ARM64 DMG Installer对应版本 注&#xff1a;这里下载需要注册oracle账号&#xff0c;不过很简单&#xff0c;只需要提供邮箱即可&…

【C++】模板进阶 -- 详解

一、非类型模板参数 模板参数 分类类型形参与非类型形参。 类型形参&#xff0c;即出现在模板参数列表中&#xff0c;跟在 class 或者 typename 之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类&#xff08;函数&#xff09;模板的一个参数&#xff0c;在类…

基于SSM的毕业生就业管理平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

2023年,考PMP用处大吗?

就本身PMP的价值而言&#xff0c;不管到多少年&#xff0c;跟新迭代下&#xff0c;用处都是很大的&#xff0c;就看你会不会用。 PMP会让你学到一套系统的项目管理的流程&#xff0c;还有作为项目管理人士该具备的素质和技能&#xff0c;这就是使得&#xff0c;即便从未接触过…