前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring依赖注入@Autowired深层原理、源码级分析,感受DI带来的编程之美【享学Spring】

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

作者头像
YourBatman
发布2019-09-03 16:03:20
1.9K2
发布2019-09-03 16:03:20
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦

前言

关于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

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

代码语言:javascript
复制
@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去完成解析结果的

代码语言:javascript
复制
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
解析注解元信息阶段
代码语言:javascript
复制
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方法代替(这个方法名语义更清晰,单纯的方法名的改动而已,内容无任何变动~~)

代码语言:javascript
复制
// @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内部类,体现出非常高的内聚性:

代码语言:javascript
复制
	// 它的宿主类是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大量的使用到了转换、适配、委托等机制。因此最终最最最重要的一行代码无非是这一句:

代码语言:javascript
复制
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

委托AutowireCapableBeanFactory来获取到依赖值value,从而最终完成注入(反射执行注入~)。

so,其实最核心还是在Bean工厂里,也就是它的唯一内建实现类DefaultListableBeanFactory

DefaultListableBeanFactory解析依赖值

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

代码语言:javascript
复制
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;
		}
	}
	...
}

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

第一句是:

代码语言:javascript
复制
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName)

它会解析@Lazy这个注解,来创建代理对象。而如果它已经创建了,就不会执行第二句了。

关于这句代码的详细解释、分析,请参阅(强烈建议阅读一下本文):

【小家Spring】Spring依赖注入(DI)核心接口AutowireCandidateResolver深度分析,解析@Lazy、@Qualifier注解的原理

第二句:(重中之重)

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

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

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

代码语言:javascript
复制
// 此处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工厂用于处理依赖关系,获取依赖值的核心方法,它有两个重载实现:

代码语言:javascript
复制
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;
}

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

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

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

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


为什么@Autowired没有生效?

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

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

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

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

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


总结

Spring DI机制着实解放了我们java工程师,相信小伙伴们都有这种感觉:自动用上了Spring,现在很少自己new对象了,想要什么都是容器注入给我们(包括方法入参也是这个理论)。

这是一种编程方式、编程思想的转变,极大的提高了效率,和解放了程序员的双手,不可谓不优秀啊~

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年06月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 关于Spring的依赖注入(DI)
  • AutowiredAnnotationBeanPostProcessor
    • 准备
      • 源码分析
        • 解析注解元信息阶段
        • 注入阶段
        • 为什么@Autowired没有生效?
        • 总结
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档