Spring依赖注入populateBean方法和@Autowired原理分析

前言

Spring的依赖注入(DI):为某个对象的外部资源赋值,注入某个对象所需要的外部资源(包括对象、资源、常量数据等)。
依赖注入:Dependency Injection,简称DI,说白了就是利用反射机制为类的属性赋值的操作。

@Autowired的实际应用

@Autowired是spring用来进行内部注入的:他注入的值必须存在spring容器中

集合对象注入的查询过程

如果是数组或容器类型的话,Spring可以将所有与目标类型匹配的bean实例都注入进去,不需要判断

public class Father {
@Autowired
private List<Son> stringSon;
@Configuration
public class RootConfig {
    @Bean 
	public List<Son> sonList(){
		return new ArrayList<>();
	}
	@Bean
	public Son son1(){
        return new Son();
	}
	@Bean
	public Son son2(){
          return new Son();
	}
}

容器启动中,spring会将son1和son2加入Father的stringSon集合中。但是son1和son2在stringSon集合的顺序遵循容器中相应目标bean定义的注册顺序,如果我们想使数组或列表中的项目以特定顺序排序,则可以使用@Order或标准@Priority

@Order:默认是最低优先级,值越小优先级越高

@Order(2)
@Bean
public Son son1(){
   //...忽略代码
}

@Order(1)
@Bean
public Son son2(){
     //...忽略代码
}

普通javaBean对象注入的查询过程

1、首先在容器中查询对应类型的bean ,如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
2、如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
3、如果容器中存在多个同种类型bean,那就装配别名相同的,如果找不到别名相同的在这种情况下@Autowired(required=false)也会报错。

非集合范性对象注入的查询过程

1、首先在容器中查询对应类型和范性的bean ,如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
2、如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
3、如果容器中存在多个同种类型和范性bean,那就装配别名相同的,如果找不到别名相同的在这种情况下@Autowired(required=false)也会报错。

这种情况的解决方法目前有2种

1、使用 @Qualifier直接点名要哪个

@Qualifier("car1")
@Autowired
private Car car;

2、@Primary 告诉spring容器,如果进行自动装配,那么优先选这个bean

  • 注意:@Primary只能标注到一个同类型的Bean上
@Primary
@Bean
public Car car2(){
       Car car = new Car();
       car.setName("大众");
       return car;
}

标注@Autowired注解的位置对spring对影响

1、标注在构造器上

从Spring Framework4.3开始,@Autowired如果目标bean仅定义一个构造函数作为开始,则不再需要在此类构造函数上添加注释。但是,如果有多个构造函数可用,则必须至少注释一个构造函数,@Autowired以指示容器使用哪个构造函数。

如果我们想spring生产bean的实例时,不要用无参构造器,那么只需在我们想要的执行的构造器上加上@Autowired
其形参是从spring容器中注入,如果spring容器没有其形参值的注入就报错,比如这样

public Father(){
     System.out.println("Father...init")
}
@Autowired
public Father( Son son){
       System.out.println("Father.String name..init");
}

这时我们可以使用@Autowired(required=false),这时如果spring容器没有son,那么spring初始化对象就会使用无参构造器,如果我还想使用有参构造器,这时我们需这样写

@Autowired
public Father(@Nullable  Son son){
       System.out.println("Father.String name..init")
}

spring容器没有son,也会执行这个构造器,注意:@Nullable只有在spring注入时才有这个效果,其他情况下是做提示用的

2、标注在方法上

Spring会先实例化所有Bean,然后根据配置进行扫描,当检测到@Autowired后进行注入,注入时调用这个方法。

3、标注在方法形参上和标准在类的成员属性上

如果放在形参旁边,表示此参数赋值是从IOC容器中寻找(4.3才有),如果此方法上有@Bean注解,则可以省略@Autowired
Spring创建当前类对象,就会调用此方法完成方法参数的赋值,方法参数的赋值是从IOC容器中寻找

解析注解元信息阶段

关于@Autowired这个注解,我们再熟悉不过了,经常跟@Resource来做对比,这篇文章我们不讨论两者有何异同,仅分析@Autowired的深层原理,解析@Resource注解的是CommonAnnotationBeanPostProcessor
在这里插入图片描述
由此继承图标我们能得出如下结论:

实现了InstantiationAwareBeanPostProcessor接口,所以可以介入到Bean的实例化前后
实现了BeanPostProcessor,所以介入到Bean的初始化前后
实现了MergedBeanDefinitionPostProcessor,说明它可以合并bean的定义信息,介入到Bean调用构造后
实现了BeanFactoryAware,实现了PriorityOrdered

源码分析

在Bean的创建过程中,调用Bean的构造器后,会调用方法MergedBeanDefinitionPostProcessorpostProcessMergedBeanDefinition()完成了对该bean中所有的依赖注入的属性、方法完成了原始元信息的转换,把依赖注入的相关注解全都转换成了InjectionMetadata,这样后面的使用过程中将不再需要再和具体注解打交道,而是做着一些和业务无关的动作即可。

  • InjectionMetadata:这个是注入元数据,包含了目标Bean的Class对象,和注入元素(InjectionElement)集合,通过他我们可以知道某个bean的那个属性或者方法要进行注入。
  • InjectionElement:是要被注入的属性或者方法的描述

对于@Autowired@value@Inject的解析是使用MergedBeanDefinitionPostProcessor的子类AutowiredAnnotationBeanPostProcessor

public class AutowiredAnnotationBeanPostProcessor extends ... implements ... {

// 该处理器支持解析的注解们,通过其构造器我们得知默认支持的是3个(当然你可以自己添加自定义的依赖注入的注解   这点非常强大)
	private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
	private String requiredParameterName = "required";
	private boolean requiredParameterValue = true;

	private int order = Ordered.LOWEST_PRECEDENCE - 2;

	@Nullable
	private ConfigurableListableBeanFactory beanFactory;
    // 对@Lookup方法的支持
	private final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
    //构造函数注入
	private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256);
    // 方法注入、字段filed注入  本文的重中之重
	// 此处InjectionMetadata这个类非常重要,到了此处@Autowired注解含义已经没有了,完全被准备成这个元数据了  所以方便我们自定义注解的支持
	// InjectionMetadata持有targetClass、Collection<InjectedElement> injectedElements等两个重要属性
	// 其中InjectedElement这个抽象类最重要的两个实现为:AutowiredFieldElement和AutowiredMethodElement
	private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);


	// 这是它唯一构造函数  默认支持下面三种租借(当然@Inject需要额外导包)
	// 请注意:此处@Value注解也是被依赖注入解析的~~~~~~~~
	// 当然如果你需要支持到你的自定义注解,你还可以调用下面的set方法添加。。
	public AutowiredAnnotationBeanPostProcessor() {
		this.autowiredAnnotationTypes.add(Autowired.class);
		this.autowiredAnnotationTypes.add(Value.class);
		try {
			this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
			logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}


	// 下面两个方法可以自定义支持的依赖注入注解类型,他会删除旧。
	public void setAutowiredAnnotationType(Class<? extends Annotation> autowiredAnnotationType) {
		Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null");
		this.autowiredAnnotationTypes.clear();
		this.autowiredAnnotationTypes.add(autowiredAnnotationType);
	}
	public void setAutowiredAnnotationTypes(Set<Class<? extends Annotation>> autowiredAnnotationTypes) {
		Assert.notEmpty(autowiredAnnotationTypes, "'autowiredAnnotationTypes' must not be empty");
		this.autowiredAnnotationTypes.clear();
		this.autowiredAnnotationTypes.addAll(autowiredAnnotationTypes);
	}


   // bean工厂必须是ConfigurableListableBeanFactory的(此处放心使用,唯独只有SimpleJndiBeanFactory不是它的子类而已~)
	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
			throw new IllegalArgumentException(
					"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory);
		}
		this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
	}


    // 第一个非常重要的核心方法~~~  
	//它负责1、解析@Autowired等注解然后转换
	// 2、把注解信息转换为InjectionMetadata然后缓存到上面的injectionMetadataCache里面
	// postProcessMergedBeanDefinition的执行时机非常早,在doCreateBean()前部分完成bean定义信息的合并
	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
		metadata.checkConfigMembers(beanDefinition);
	}

// 方法名为查找到该bean的依赖注入元信息,内部只要查找到了就会加入到缓存内,下次没必要再重复查找了~
	// 它是一个模版方法,真正做事的方法是:buildAutowiringMetadata  它复杂把标注有@Autowired注解的属性转换为Metadata元数据信息  从而消除注解的定义
	// 此处查找包括了字段依赖注入和方法依赖注入~~~
	private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		// 返回类名作为缓存键,以便与自定义调用方向后兼容。
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// 首先从缓存中查找
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	    //如果在缓存中查询不到或者查询的不是当次查询想要的
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
			   //双重检查
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					//标注autowiredAnnotationTypes集合中注解的属性转换为Metadata元数据信息  从而消除注解的定义
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

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

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
            //查询成员变量
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
			    //找到标注有autowiredAnnotationTypes的注解,(默认查询标注@Autowired或者@value的字段)
				AnnotationAttributes ann = findAutowiredAnnotation(field);
				if (ann != null) {
				     //静态变量不能进行注入
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					boolean required = determineRequiredStatus(ann);
					//待注入成员属性使用AutowiredFieldElement表示
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});
            //查询方法
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
				     // static方法不好使
					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);
					//待注入方法使用AutowiredMethodElement表示
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});

            // 小细节:父类的都放在第一位,所以父类是最先完成依赖注入的
			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);
		return new InjectionMetadata(clazz, elements);
	}

1、把javaBean中待注入的非静态成员属性包装成AutowiredFieldElement
2、把javaBean中待注入的非静态方法包装成AutowiredMethodElement
3、把他他们放到List<InjectionMetadata.InjectedElement>集合中,且父类待注入的放在前面
4、把List<InjectionMetadata.InjectedElement>集合放在InjectionMetadata中,表示这个javaBean待注入的信息,到这里spring就不在关注@Autowired@Value等注解了

注入阶段

我们知道在Bean的创建过程中,完成Bean的实例化后,会调用方法AbstractAutowireCapableBeanFactorypopulateBean()完成对Bean的属性赋值,从而就会触发InstantiationAwareBeanPostProcessor.postProcessPropertyValues()方法给属性进行赋值,这处也就是本步骤的入口~

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		if (bw == null) {// 对实例做的一个判空校验}
		boolean continueWithPropertyPopulation = true;

		//给InstantiationAwareBeanPostProcessors最后一次机会在属性注入前修改Bean的属性值
		//具体通过调用postProcessAfterInstantiation方法,如果调用返回false,表示不必继续进行依赖注入,直接返回
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				
					//postProcessAfterInstantiation 这个方法返回true,后面的处理器才会继续执行,单反返回false,后面的就不会再执行了
					//并且continueWithPropertyPopulation 打上标记表示false,也就是说后面的属性复制就不会再执行了
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						continueWithPropertyPopulation = false;
						break;
					}
				}
			}
		}
		// 处理器若告知说不用继续赋值了,那就以处理器的结果为准即可
		if (!continueWithPropertyPopulation) {
			return;
		}

		//pvs提供属性的读写操作实现,同时可以通过调用构造函数实现深拷贝
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

		//根据Bean配置的依赖注入方式完成注入,默认是0,即不走以下逻辑,所有的依赖注入都需要在xml(或者@Bean中)文件中有显式的配置
		//如果设置了相关的依赖装配方式,会遍历Bean中的属性,根据类型或名称来完成相应注入,无需额外配置
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			// 深拷贝当前已有的配置
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

			// 根据名称进行注入(见下)
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// 根据类型进行注入(见下)
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			//结合注入后的配置,覆盖当前配置
			pvs = newPvs;
		}

		// 显然hasInstAwareBpps=true,
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		//是否进行依赖检查  默认值就是None  所以此处返回false,表示不需要依赖检查(关于依赖检查的4种模式,建议使用@Required来显示控制)
		//@Required注解作用于Beansetter方法上,用于检查一个Bean的属性的值在配置期间是否被赋予或设置(populated)
		boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

		if (hasInstAwareBpps || needsDepCheck) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			// 过滤出所有需要进行依赖检查的属性编辑器
			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);

			// 在这个节点上:调用了InstantiationAwareBeanPostProcessor#postProcessPropertyValues方法,
			// 若返回null,整个populateBean方法就结束了=============
			if (hasInstAwareBpps) {
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if (bp instanceof InstantiationAwareBeanPostProcessor) {
						InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
						// 关于postProcessPropertyValues的实现,有几个处理器是非常关键的:
						// 比如AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor等等,且看下面的分解
						pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						// 若返回null,Spring表示你已经属性值都设置好了,那他也不再管了
						if (pvs == null) {
							return;
						}
					}
				}
			}
			// 显然,现在大多数情况下,都不会在check这个了
			if (needsDepCheck) {
				checkDependencies(beanName, mbd, filteredPds, pvs);
			}
		}

		// 将pvs上所有的属性填充到BeanWrapper对应的Bean实例中
		// 注意:这一步完成结束后为止。我们的HelloServiceImpl这个Bean依赖的parent,还只是RuntimeBeanReference类型,还并不是真实的Parent这个Bean
		//在Spring的解析段,其它容器中是没有依赖的Bean的实例的,因此这个被依赖的Bean需要表示成RuntimeBeanReferenc对象,并将它放到BeanDefinition的MutablePropertyValues中。
		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
		
	}

这是核心阶段,也是最为复杂的阶段,当然前面的解析已经为本步骤做好了元数据InjectionMetadata的铺垫。

// @since 2.5
public class AutowiredAnnotationBeanPostProcessor extends ... implements ... {
	...	
	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		// 从缓存中取出这个bean对应的依赖注入的元信息~
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		//(生路异常处理部分代码)所以事情都委托给了InjectionMetadata 的inject方法
		// 此处注意InjectionMetadata是会包含多个那啥的~~~(当然可能啥都没有  没有依赖注入的东东)
		//InjectionMetadata.inject内部查看也十分简单:最终都还是委托给了InjectedElement.inject实例去处理的
		metadata.inject(bean, beanName, pvs);
		return pvs;
	}

}

InjectionMetadata的inject的方法,其底层是InjectedElement的inject,这个抽象类有好几个实现,通过上面的源码分析,

我们知道对于成员属性的注入,实际作用的是InjectedElement的子类AutowiredFieldElement

我们知道对于方法的注入,实际作用的是InjectedElement的子类AutowiredMethodElement

这个类继承自静态抽象内部类InjectionMetadata.InjectedElement,并且它还是AutowiredAnnotationBeanPostProcessor的private内部类。

在此以成员属性的注入的注入为例子

private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
		private final boolean required;
		//判断当前
		private volatile boolean cached = false;
		@Nullable
		private volatile Object cachedFieldValue;

		public AutowiredFieldElement(Field field, boolean required) {
			super(field, null);
			this.required = required;
		}
        //进行属性注入的方法
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			// 显然此处父类的member就指的是filed
			Field field = (Field) this.member;
			Object value;
			// 走缓存,关于cachedFieldValue的值
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			else {
				// 每个Field都包装成一个DependencyDescriptor
				// 此处包装成它后,显然和元数据都无关了,只和Field有关了  完全隔离
				//DependencyDescriptor是要被注入的属性或者方法的信息。如名字,他属于的bean的class
				DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
				desc.setContainingClass(bean.getClass());
				Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
				Assert.state(beanFactory != null, "No BeanFactory available");
				// 转换器使用的bean工厂的转换器~~~
				TypeConverter typeConverter = beanFactory.getTypeConverter();
				try {
					// 获取依赖的value值的工作  最终还是委托给beanFactory.resolveDependency()去完成的~~~~
					value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
				}
				// 下面代码是把缓存值缓存起来  让同一个Field注入多次能提高效率
				synchronized (this) {
					if (!this.cached) {
						// 可以看到value!=null并且required=true才会进行缓存的处理
						if (value != null || this.required) {
							this.cachedFieldValue = desc;
							// 简单的说就是注册到bean工厂去,比如此处b是依赖a的  所以就注册这个依赖关系进去了
							registerDependentBeans(beanName, autowiredBeanNames);
							// autowiredBeanNames里可能会有别名的名称~~~所以size可能大于1
							if (autowiredBeanNames.size() == 1) {
								String autowiredBeanName = autowiredBeanNames.iterator().next();
								// beanFactory.isTypeMatch挺重要的~~~~因为@Autowired是按照类型注入的
								//从这里可以看出,当容器中只有一个bean时,按照类型注入
								if (beanFactory.containsBean(autowiredBeanName) &&
										beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
									this.cachedFieldValue = new ShortcutDependencyDescriptor(
											desc, autowiredBeanName, field.getType());
								}
							}
						}
						else {
							this.cachedFieldValue = null;
						}
						this.cached = true;
					}
				}
			}
			// 不为null,就完成最终的set值  利用反射给filed属性赋值~~~~
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}
	}

1、如果已经缓存过,先从缓存中查询注入的值
2、如果没有缓存过,利用DefaultListableBeanFactory的resolveDependency方法查询要注入的值
3、利用反射,调用JavaBean的set方法进行赋值

从源码中也能发现一个特点,Spring大量的使用到了转换、适配、委托等机制。因此查询值的任务最终是这一行代码:

value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

其是委托AutowireCapableBeanFactory来获取到依赖值value,从而最终完成注入(反射执行注入~)。so,其实最核心还是在Bean工厂里,也就是它的唯一内建实现类DefaultListableBeanFactory,其过程如下

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		//此处使用的是DefaultParameterNameDiscoverer 来获取参数名
		// 这就是为什么我们使用@Autowired注入,即使有多个同类型的Bean,也可以通过field属性名进行区分的根本原因(可以不需要使用@Qualifier注解)
		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		// 支持Optional  原来还是doResolveDependency  暂略
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		} 
		// 原理也是doResolveDependency  
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		} else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		} else { // 绝大部分情况下  肯定走到这里~~~~
				
			// 此处特别特别的需要重视:这是@Lazy支持的根本原因~~
			// 此处若通过AutowireCandidateResolver解析到了值就直接返回了(若标注了@Lazy,此处的result将不会为null了~~~)
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);

			// doResolveDependency是绝大多数情况下  最终会去执行的代码(若result仍旧为null的话)
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}
	...
}

截止到这,整个流程中有两句非常重要的代码不容忽视:

第一句是:

Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName)

它会解析@Lazy这个注解,来创建代理对象。而如果它已经创建了,就不会执行第二句了。
关于这句代码的详细解释、分析。
请参阅: Spring依赖注入(DI)核心接口AutowireCandidateResolver深度分析,解析@Lazy、@Qualifier注解的原理

第二句:(重中之重)

result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);

绝大多数情况下,肯定会经由我们的DefaultListableBeanFactory的doResolveDependency()方法来处理,因此这个方法的实现才是重中之重。

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

		// 记录注入点,其实使用的ThreadLocal~
		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			// 只有ShortcutDependencyDescriptor实现了resolveShortcut方法,其实就是根据
			// 实现也就一句话:beanFactory.getBean(this.shortcut, this.requiredType)
			// ShortcutDependencyDescriptor实在inject完成后创建的,就是有缓存的效果~~~
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}

			// interface com.fsx.dependency.AInterface
			Class<?> type = descriptor.getDependencyType();

			// 拿到@Value注解的value值(是个字符串)  若没有标注@Value  显然就不用那啥了
			// 从此处其实也可以看出,@Value注解的优先级对于找到bean来说还是蛮高的
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);

			// ============ 这部分主要是解析@Value注解
			// 解析它的占位符,解析它的SpEL表达式
			// 相关处理类曹靠BeanExpressionResolver和StandardBeanExpressionResolver  StandardEvaluationContext等
			// 因为关于@Value的文章里详细解过,此处一笔带过~~~
			// 备注:QualifierAnnotationAutowireCandidateResolver会处理@Qualifier和@Value
			//QualifierAnnotationAutowireCandidateResolver#getSuggestedValue()
			//先拿出@Value注解的值  如果为null再去拿Method里这个注解的值~~~ 最终返回~  所以@Value也是可以标注在方法上的
			// 注意此处:若是@Value  这里返回值肯定是String  但是若是@Autowired此处返回值就可能是对象了~
			if (value != null) {
				if (value instanceof String) {
				// 使用StringValueResolver处理${}占位符~
					// 所以我们常用的只使用@Value("${xxx}")这样来注入值或者你就是个字面量值,到这一步就已经完事了~解析完成  
					// 若你是个el表达式  或者文件资源Resource啥的,会继续交给下面的beanExpressionResolver处理,所以它是处理复杂类型的核心~
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ?
							getMergedBeanDefinition(beanName) : null);
					// 此处注意:处理器是BeanExpressionResolver~~~~它是处理@Value表达式的核心方法
					// 它的默认值是:StandardBeanExpressionResolver#evaluate
					// 这里面就会解析
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				try {
					return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
				} catch (UnsupportedOperationException ex) {
					// A custom TypeConverter which does not support TypeDescriptor resolution...
					return (descriptor.getField() != null ?
							converter.convertIfNecessary(value, type, descriptor.getField()) :
							converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
				}
			}
			


			// 此处处理的是多值注入的情况,比如注入Stream<Object>、Map、Array、Collection等等  Spring都是支持的
			// 需要稍微注意一点,Stream这种类型的注入在Spring4以上才得到支持的
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}

			// 显然绝大部分情况下,都会走到这里(因为大部分我们都是单值注入~)
			// findAutowireCandidates可以说又是整个依赖注入的灵魂之一~~~~ 它的查找步骤简述如下:
			//1、BeanFactoryUtils.beanNamesForTypeIncludingAncestors() 找到这种类型的所有的beanNames(candidateNames)(可能有多个哟,但大多数情况下只有一个)
			//2、处理resolvableDependencies比如ApplicationContext的依赖,让他们也能够正常注入进去(他们可不作为bean存在容器里~)
			//3、遍历candidateNames:检查它是否可以被依赖、容器内是否存在bean定义(或者Singleton) 若符合,getBean()出来放在map里
			//4、若返回的Map不为Empty()了,直接return  表示找到了(当然还可能是多个~~)
			// 若返回的还是Empty,那就继续检查requiredType是否为Map、Collection等类型,从它里面去找。。
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			// 所以matchingBeans证明没有找到匹配的,但requied=true,所以此处就抛出异常了~
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;

			// 若有多个匹配
			// 需要注意的是:@Qualifier注解在上面就已经生效了~~~~因为AutowireCandidateResolver.isAutowireCandidate是在上面生效的
			if (matchingBeans.size() > 1) {
				// 由它进行判别  从弱水三千中  取出一瓢
				// 1、是否标注有@Primary  有这种bean就直接返回(@Primary只允许标注在一个同类型Bean上)
				// 2、看是否有标注有`javax.annotation.Priority`这个注解的
				// 3、根据字段field名,去和beanName匹配  匹配上了也行(这就是为何我们有时候不用@Qulifier也没事的原因之一)
				// 此处注意:descriptor.getDependencyName()这个属性表示字段名,靠的是`DefaultParameterNameDiscoverer`去把字段名取出来的~
				//若出现多个Bean,将由下面方法去匹配和决定
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {

						// 此处抛出异常:NoUniqueBeanDefinitionException
						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 { 
				// 仅仅只匹配上一个,走这里 很简单  直接拿出来即可
				// 注意这里直接拿出来的技巧:不用遍历,直接用iterator.next()即可
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}
             // 把找到的autowiredBeanName 放进去
			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			if (instanceCandidate instanceof Class) {
				// 此处getBean() 拿到该类型的实例对象了~~~
				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);
		}
	}
}

通过上面代码的分析,其中查询待注入的bean的方法是这个,

Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
protected Map<String, Object> findAutowireCandidates( String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
		// 获取类型匹配的bean的beanName列表(包括父容器,但是此时还没有进行泛型的精确匹配)
		String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
         //存放结果的Map(beanName -> bena实例)  最终会return的
		Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
		//处理resolvableDependencies比如ApplicationContext的依赖,让他们也能够正常注入进去(他们可不作为bean存在容器里~
		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;
				}
			}
		}
		//遍历candidateNames:检查它是否可以被依赖、容器内是否存在bean定义(或者Singleton) 若符合,getBean()出来放在map里
		for (String candidate : candidateNames) {
		// isAutowireCandidate:这个方法非常的关键,判断该bean是否允许注入进来。泛型的匹配就发生在这个方法里,下面会详解
			if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
				addCandidateEntry(result, candidate, descriptor, requiredType);
			}
		}
		// 若返回的还是Empty,那就继续检查requiredType是否为Map、Collection等类型,从它里面去找。。。
		if (result.isEmpty()) {
			boolean multiple = indicatesMultipleBeans(requiredType);
			//如果第一次传球找不到任何东西,请考虑回退匹配。。。
			DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
			for (String candidate : candidateNames) {
			//不是自引用 && 符合注入条件
			// 自引用的判断:找到的候选的Bean的名称和当前Bean名称相等 或者 当前bean名称等于工厂bean的名称~~~~~~~
			// isAutowireCandidate:这个方法非常的关键,判断该bean是否允许注入进来。泛型的匹配就发生在这个方法里,下面会详解
				if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
						(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
					addCandidateEntry(result, candidate, descriptor, requiredType);
				}
			}
			if (result.isEmpty() && !multiple) {
				//把自我推荐当作最后一关。。。
                //但是在依赖项集合的情况下,不是同一个bean本身。
				for (String candidate : candidateNames) {
					if (isSelfReference(beanName, candidate) &&
							(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
							isAutowireCandidate(candidate, fallbackDescriptor)) {
						addCandidateEntry(result, candidate, descriptor, requiredType);
					}
				}
			}
		}
		//若返回的Map不为Empty()了,直接return  表示找到了(当然还可能是多个~~)
		return result;
	}

他能告诉我们待注入的bean有几个,如果待注入的bean只有一个,不用说,就他了,但是如果多个待注入bean呢?这时候就要看这段代码

autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
		Class<?> requiredType = descriptor.getDependencyType();
		// 看看传入的Bean中有没有标注了@Primary注解的,有的话,返回他的bean名字
		String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
		// 如果找到了 就直接返回
		// 由此可见,@Primary的优先级还是非常的高的
		if (primaryCandidate != null) {
			return primaryCandidate;
		}
		//找到一个标注了javax.annotation.Priority注解的。(备注:优先级的值不能有相同的,否则报错)
		String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
		if (priorityCandidate != null) { 
			return priorityCandidate;
		}
		// 这里是最终的处理(相信绝大部分情况下,都会走这里~~~~~~~~~~~~~~~~~~~~)
		// 此处就能看出resolvableDependencies它的效能了,他会把解析过的依赖们缓存起来,不用再重复解析了
		for (Map.Entry<String, Object> entry : candidates.entrySet()) {
			String candidateName = entry.getKey();
			Object beanInstance = entry.getValue();
			
			// 到这一步就比较简单了,matchesBeanName匹配上Map的key就行。
			// 需要注意的是,bean可能存在很多别名,所以只要有一个别名相同,就认为是能够匹配上的 
			//descriptor.getDependencyName() 这个特别需要注意的是:如果是字段,这里调用的this.field.getName() 直接用的是字段的名称
			// 因此此处我们看到的情况是,我们采用@Autowired虽然匹配到两个类型的Bean了,即使我们没有使用@Qualifier注解,也会根据字段名找到一个合适的(若没找到,就抱错了)
			if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
					matchesBeanName(candidateName, descriptor.getDependencyName())) {
				return candidateName;
			}
		}
		return null;
	}
发布了34 篇原创文章 · 获赞 0 · 访问量 1370

猜你喜欢

转载自blog.csdn.net/qq_41071876/article/details/104514224