专栏首页BAT的乌托邦Spring依赖注入@Autowired深层原理、源码级分析,感受DI带来的编程之美【享学Spring】

Spring依赖注入@Autowired深层原理、源码级分析,感受DI带来的编程之美【享学Spring】

前言

关于Spring IOC的依赖注入(DI机制),之前虽有过分析,但总感觉一直落了一块:对@Autowired注解元数据的解析部分。

本篇文章重在拾遗,并且从依赖注入整体的流程上进行把握。因为个人觉得依赖注入对于Spring框架来说太重要了,所以用多少笔墨,强调多少遍都不为过。so希望本篇文章能继续为大家服务,帮助到大家~

在继续这篇文章之前,强烈建议还赌自己是"小白"的同学先观看博文: 【小家Spring】Spring依赖注入(DI)核心接口AutowireCandidateResolver深度分析,解析@Lazy、@Qualifier注解的原理

关于Spring的依赖注入(DI)

注入为某个对象的外部资源赋值,注入某个对象所需要的外部资源(包括对象、资源、常量数据等)。

注意对这里我所说的外部资源的理解,理解了就好,不用刻意的咬文嚼字~

依赖注入Dependency Injection,简称DI,说白了就是利用反射机制为类的属性赋值的操作。

关于@Autowired这个注解,我们再熟悉不过了,经常跟@Resource来做对比,这篇文章我们不讨论两者有何异同,仅分析@Autowired深层原理

AutowiredAnnotationBeanPostProcessor

准备

解析@Resource注解的不是这个类,而是CommonAnnotationBeanPostProcessor,但本文只会以AutowiredAnnotationBeanPostProcessor为例做深入分析~~~(解析@Autowired

为了更好的说明问题,以下面这个具体实例进行讲解:

@Service
public class A implements AInterface {

    @Async
    @Override
    public void funA() {
        System.out.println("线程名称:" + Thread.currentThread().getName());
    }
}

@Service
public class B implements BInterface {

    @Autowired
    private AInterface a;

    @Override
    public void funTemp() {
        System.out.println("线程名称:" + Thread.currentThread().getName());
    }

    @Override
    public void funB() {
        System.out.println("线程名称:" + Thread.currentThread().getName());
    }

}

源码分析

对于此类,其实@Autowired的javadoc上就有提到:它是靠AutowiredAnnotationBeanPostProcessor去完成解析结果的

Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor} class (which, by default, checks for the presence of this annotation).

先看一下AutowiredAnnotationBeanPostProcessor它的继承图表:

由此继承图标我们能得出如下结论:

  1. 实现了InstantiationAwareBeanPostProcessor接口,所以可以介入到Bean的实例化前后
  2. 实现了BeanPostProcessor,所以介入到Bean的初始化前后
  3. 实现了MergedBeanDefinitionPostProcessor,说明它可以合并bean的定义信息
  4. 实现了BeanFactoryAware,实现了PriorityOrdered

解析注解元信息阶段

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
	
	// 该处理器支持解析的注解们~~~(这里长度设置为4)  默认支持的是3个(当然你可以自己添加自定义的依赖注入的注解   这点非常强大)
	private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
	// @Autowired(required = false)这个注解的属性值名称
	// A 'required' dependency means that autowiring should fail when no beans are found.
	private String requiredParameterName = "required";
	// 这个值一般请不要改变(若改成false,效果required = false的作用是相反的了)
	private boolean requiredParameterValue = true;
	private int order = Ordered.LOWEST_PRECEDENCE - 2;

	// 对@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);
	}
	... // 省略其余get/set方法

	// 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) {
		// findAutowiringMetadata方法重要,完成了解析注解、缓存下来的操作
		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);
					}
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

	// 这里我认为是整个依赖注入前期工作的精髓所在,简单粗暴的可以理解为:它把以依赖注入都转换为InjectionMetadata元信息,待后续使用
	// 这里会处理字段注入、方法注入~~~
	// 注意:Autowired使用在static字段/方法上、0个入参的方法上(不会报错 只是无效)
	// 显然方法的访问级别、是否final都是可以正常被注入进来的~~~
	private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		// 小细节:这里是个do while循环,所以即使在父类,父父类上依赖注入依旧是好使的(直到Object后停止)
		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				AnnotationAttributes ann = findAutowiredAnnotation(field);
				if (ann != null) {
					// static属性不好使
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					//解析required属性(若存在)  最终封装成AutowiredFieldElement
					boolean required = determineRequiredStatus(ann);
					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里封装了一个PropertyDescriptor(比字段多了一个参数)
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});

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

	// 只要方法/属性上但凡标注有一个注解,就立马返回了~~(so你标注多个最终生效的只会有一个哦)
	@Nullable
	private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
		if (ao.getAnnotations().length > 0) {  // autowiring annotations have to be local
			for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
				AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
				if (attributes != null) {
					return attributes;
				}
			}
		}
		return null;
	}
	// 小细节这个方法是protected的
	protected boolean determineRequiredStatus(AnnotationAttributes ann) {
		return (!ann.containsKey(this.requiredParameterName) || this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
	}
	... // 关于内部类inject的最终可以放在下面的重点
}

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

注入阶段

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

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

注意:Spring5.1之后把此方法@Deprecated了,用postProcessProperties方法代替(这个方法名语义更清晰,单纯的方法名的改动而已,内容无任何变动~~)

// @since 2.5
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
	...
	@Deprecated // 标注为过期,直接调用postProcessProperties方法
	@Override
	public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
		return postProcessProperties(pvs, bean, beanName);
	}	
	@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;
	}

}

综上能够发现,最终依赖注入实际做事的是InjectedElement,这个抽象类有好几个实现,此处我们以使用最为广泛的AutowiredFieldElement进行说明

AutowiredFieldElement实现属性依赖注入

这个类继承自静态抽象内部类InjectionMetadata.InjectedElement,并且它还是AutowiredAnnotationBeanPostProcessor的private内部类,体现出非常高的内聚性:

	// 它的宿主类是AutowiredAnnotationBeanPostProcessor 高内聚低耦合
	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;
		}

		// 核心方法:字段的依赖注入
		@Override
		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
				// 如果是Method包装成DependencyDescriptor,毕竟一个方法可以有多个入参
				// 此处包装成它后,显然和元数据都无关了,只和Field有关了  完全隔离
				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()去完成的~~~~
					// 这个接口方法由AutowireCapableBeanFactory提供,它提供了从bean工厂里获取依赖值的能力~
					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才会进行缓存的处理
						// 按照上例 此处value值为A@2277实例
						if (value != null || this.required) {
							this.cachedFieldValue = desc; // 可以看到缓存的值是上面的DependencyDescriptor对象~~~~


							// 这个方法是宿主类AutowiredAnnotationBeanPostProcessor的方法
							// 简单的说就是注册到bean工厂去,比如此处b是依赖a的  所以就注册这个依赖关系进去了
							// 参考this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
							registerDependentBeans(beanName, autowiredBeanNames);

							// autowiredBeanNames里可能会有别名的名称~~~所以size可能大于1
							if (autowiredBeanNames.size() == 1) {

								// beanFactory.isTypeMatch挺重要的~~~~因为@Autowired是按照类型注入的
								String autowiredBeanName = autowiredBeanNames.iterator().next();
								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);
			}
		}
	}

前面准备好的注解的、需要注入的元数据信息,这一步使用执行注入。 从源码中也能发现一个特点,Spring大量的使用到了转换、适配、委托等机制。因此最终最最最重要的一行代码无非是这一句:

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

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

DefaultListableBeanFactory解析依赖值

分离关注,本处只看它解析依赖值的方法resolveDependency()

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	...
	@Override
	@Nullable
	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我建议小伙伴先看下一个章节~~~
			// 此处若通过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】Spring依赖注入(DI)核心接口AutowireCandidateResolver深度分析,解析@Lazy、@Qualifier注解的原理

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

看过上文你就能知道:其实getLazyResolutionProxyIfNecessary()它的底层依赖还是doResolveDependency()这个方法

看看DefaultListableBeanFactory对这个"重中之重"的实现:

// 此处autowiredBeanNames是在inject的一个空的Set
// autowired表示最终可以注入进去的bean名称们(因为可能是会有多个符合条件的)
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	...
	@Nullable
	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的文章里详细解过,此处一笔带过~~~
			if (value != null) {
				if (value instanceof String) {
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ?
							getMergedBeanDefinition(beanName) : null);
					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等类型,从它里面去找。。。(这种注入case使用太少,此处暂略~)
			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`去把字段名取出来的~
				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 { // 只有一个匹配就啥都说了  干就完了
				// 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) {
				// 此处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);
		}
	}
	...
}

说明:因为doResolveDependency()这个方法已经详细介绍过多次了,所以这里描述得相对简单。当然若还有迷糊的小伙伴,可出门左拐看看看之前的相关博文,或者底部留言,推给你~

其实本类的doResolveDependency()方法使用非常的广泛,虽然不属于接口方法,但是在DefaultListableBeanFactory类中还是public的访问权限。

我们知道Jdk以及Spring框架它对类、方法的访问权限控制得都是非常讲究的

除了接口方法resolveDependency()依赖它外,还有本类的private内部类DependencyObjectProvider也大量的使用到它,当然还少不了我上面所说的处理@Lazy注解注入的处理器类ContextAnnotationAutowireCandidateResolver.getLazyResolutionProxyIfNecessary(),它最终的根本原理也是依赖了此方法实现从而找到注入的值的~~

关于AutowireCapableBeanFactory.resolveDependency方法

这个方法是Spring Bean工厂用于处理依赖关系,获取依赖值的核心方法,它有两个重载实现:

public interface AutowireCapableBeanFactory extends BeanFactory {

	// 其实这个方法最终调用的是下面这个方法
	@Nullable
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
	@Nullable
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
}

这里主要是关注依赖此方法的地方,整理出来好让我们能有个全局性的把控,列出如下:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		...
		// 此方法里的autowireByType()方法依赖于resolveDependency()给它找值
		...
	}
}
// AutowiredAnnotationBeanPostProcessor 这个类,不解释
// CommonAnnotationBeanPostProcessor可见@Resource最终也是靠它

关于CommonAnnotationBeanPostProcessor它处理@Resource注解的注入,此处省略不再鳌诉了。大致逻辑基本同@Autowired的解析过程,有兴趣的可以自行研究。

不仅于此,这个处理器还能处理JSR其余注解入:@WebServiceRef@EJB等注解(它哥俩也都能实现依赖注入),以及还会处理JSR的生命周期注解@PostConstruct@PreDestroy~~~


为什么@Autowired没有生效?

这个问题是有一次小伙伴私聊问我的,我把它放在此处,希望能帮助到遇到类似情况的小伙伴们。

我们知道我们使用@Autowired注入Bean,要么就报错,要么就正常work,那么何来不生效的情况呢(不生效指的是值没注入进入,仍为null)?(注意:不考虑requied=false的情况)

我个人总结如下两点,若遇到同样问题,可从下面着手去定位:

  1. @Autowired依赖的Bean以及@Autowired所在Bean是否交给Spring容器管理了? 1. Tips:虽然依赖注入@Autowired所在的Bean并不必须得交给Spring容器管理,但此处不考虑这种case(因为我预估很少人知道这个知识点并且还能会用这个知识点,对于此知识点有兴趣的参考博文:【小家Spring】为脱离Spring IOC容器管理的Bean赋能【依赖注入】的能力,并分析原理(借助AutowireCapableBeanFactory赋能)
  2. @Autowired所在的Bean的初始化时机是否比AutowiredAnnotationBeanPostProcessor还早? 1. @Autowired注解必须靠AutowiredAnnotationBeanPostProcessor才能解析。而它虽然实现了PriorityOrdered接口,但是它毕竟还是个BeanPostProcessor,所以生效时机还是会晚于BeanFactoryPostProcessor的,所以若你在BeanFactoryPostProcessor里getBean(),那依赖注入铁定不生效呀~

关于BeanPostProcessor机制以及原理、生效时机,可参考文章:【小家Spring】注意BeanPostProcessor启动时对依赖Bean的“误伤”陷阱(is not eligible for getting processed by all…)


总结

Spring DI机制着实解放了我们java工程师,相信小伙伴们都有这种感觉:自动用上了Spring,现在很少自己new对象了,想要什么都是容器注入给我们(包括方法入参也是这个理论)。 这是一种编程方式、编程思想的转变,极大的提高了效率,和解放了程序员的双手,不可谓不优秀啊~

另外需要明白,IocDISpring中是一个等同的概念。如果非要咬文嚼字的话,控制反转是依赖注入的一部分,或者说是同一个行为偏重点不同的俩个称呼。他们是从不能的角度阐述同一个功能,描述的对象不同而已。依赖注入是从程序本身来说,控制反转是从容器来说的。

The last:如果觉得本文对你有帮助,不妨点个赞呗。当然分享到你的朋友圈让更多小伙伴看到也是被作者本人许可的~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SpringMVC学习

    Spring MVC是一个基于MVC架构的用来简化web应用程序开发的应用开发框架,它是Spring的一部分,它和Struts2一样都属于表现层的框架。

    杨肆月
  • 那些年,我们见过的 Java 服务端乱象

    移动互联网的快速发展,出现了许多新机遇,很多创业者伺机而动;随着行业竞争加剧,互联网红利逐渐消失,很多创业公司九死一生。笔者在初创公司摸爬滚打数年,接触了各式各...

    JAVA葵花宝典
  • 透过源码学习设计模式5—状态模式和Spring状态机

    状态模式即允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类,换句话说状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属...

    java达人
  • SpringIoC和SpringMVC的快速入门

    IoC和AOP是Spring框架的两大特性,IoC和MVC的流程密不可分,可以看作是面向对象编程的实现;而AOP特性则是面向切面编程的体现,也是前者的补充,所以...

    全菜工程师小辉
  • SpringBoot注解大全,收藏一波!!!

    @SpringBootApplication:包含了@ComponentScan、@Configuration和@EnableAutoConfiguration...

    用户5224393
  • Spring Boot 自定义事件

    系统启动时,执行顺序为:application starting > application prepared > application ready

    吟风者
  • 不管你是开发还是运维,微服务这些你得知道!

    这几年在Java工程师招聘时,会看到很多人的简历都写着使用了Spring Cloud做微服务实现,使用Docker做自动化部署,并且也会把这些做为自己的亮点。而...

    kubernetes中文社区
  • SSH架构/spring-security安全认证/LDAP账号打通

    参考:https://blog.csdn.net/shan9liang/article/details/8803989

    杨肆月
  • Spring Boot入门篇

    很长时间不写博客了,究其原因则是这几个月工作及生活都发生了很多事情,导致不得分心处理这些。最近难得忙里偷闲,决定还是继续更新吧。毕竟一件事情做久了,如果突然中断...

    吉林乌拉
  • Java描述设计模式(07):适配器模式

    缺省(接口)适配(Default Adapter)模式为一个接口提供缺省实现,这样子类型可以从这个缺省实现进行扩展,而不必从原有接口进行扩展。

    知了一笑

扫码关注云+社区

领取腾讯云代金券