❝其实生活中的坑,都是本身挖的,迷茫也是。愿咱们心里坚决并且不失热爱,期待与你的共同进步。java
❞
上一篇文章中,经过 createBeanInstance()
方法,最终获得了 BeanWrapper
对象。再获得这个对象以后,在Spring中,对于依赖 关系的处理,是经过 BeanWrapper
来完成的。web
这里首先作一个区分,由于在以前的很长一段时间内,我都错误的觉得 @Autowired
就是自动装配。这也就引起了我一直错误的任务Spring的自动 装配首先是 byType
而后是 byName
的。经过这段时间对于源码的阅读,我才意识到这个错误。缓存
当涉及到自动装配Bean的依赖关系时,Spring提供了4种自动装配策略。app
public interface AutowireCapableBeanFactory{
//无需自动装配 int AUTOWIRE_NO = 0; //按名称自动装配bean属性 int AUTOWIRE_BY_NAME = 1; //按类型自动装配bean属性 int AUTOWIRE_BY_TYPE = 2; //按构造器自动装配 int AUTOWIRE_CONSTRUCTOR = 3; //过期方法,Spring3.0以后再也不支持 @Deprecated int AUTOWIRE_AUTODETECT = 4; ... } 复制代码
在 xml
中定义 Bean
的时候,能够经过以下的方式指定自动装配的类型。编辑器
<bean id="demoServiceOne" class="DemoServiceOne" autowire="byName"/>
复制代码
<bean id="userService" class="UserService" autowire="byType"/>
复制代码
<bean id="user" class="User" autowire="constructor"></bean>
复制代码
若是使用了根据类型来自动装配,那么在IOC容器中只能有一个这样的类型,不然就会报错!函数
@Autowired
注解,它能够对类成员变量、方法及构造函数进行标注,完成自动装配的工做。Spring是经过 @Autowired
来实现自动装配的。 固然,Spring还支持其余的方式来实现自动装配,如:「JSR-330的@Inject注解」、「JSR-250的@Resource注解」。源码分析
经过注解的方式来自动装配 Bean
的属性,它容许更细粒度的自动装配,咱们能够选择性的标注某一个属性来对其应用自动装配。post
在这篇文章中,我将详细的分析,在一个对象中经过 @Autowired
注入或 @Resource
注入属性的处理过程。这里我仍是采起使用情形,而后画出简要 流程图,最后再是源码分析的方式来介绍本文所要涉及的知识点。flex
「情形一」:经过 @Autowired
注解对象的方式ui
@Service
public class DemoServiceTwo { @Autowired DemoServiceThree demoServiceThree; } 复制代码
「情形二」:经过 @Autowired
注解构造器的方式
@Service
public class DemoServiceTwo { DemoServiceOne demoServiceOne; @Autowired public DemoServiceTwo(DemoServiceOne demoServiceOne){ this.demoServiceOne = demoServiceOne; } } 复制代码
「情形三」:经过 @Resource
注解对象的方式
@Service
public class DemoServiceTwo { @Resource DemoServiceOne demoServiceOne; } 复制代码
「情形四」:经过 @Autowired
注解方法的方式
@Service
public class DemoServiceTwo { DemoServiceOne demoServiceOne; @Autowired public void prepare(DemoServiceOne demoServiceOne){ this.demoServiceOne = demoServiceOne; } } 复制代码
上述的四种方式是咱们在平常开发中常常用到的注入对象的方式。这四种方式,在 Spring 对应不一样的处理逻辑。
上图中描述了前面 「2.1」 中所介绍的四种情形的处理,其中蓝色线条所表示的是 @Resource
注解的处理过程。
红色线条表示 @Autowired
注解的处理过程,与之对应的有拆分红三种子状况
AutowiredFieldElement
表示注解属性的状况
AutowiredMethodElement
表示注解方法的状况
经过上述流程图,我从中找到了如下几点。经过已下几点咱们也能够区分 @Resource
和 @Autowired
。
两种注解的处理方式都是经过后置处理器来完成处理的,getBeanPostProcessors()
在咱们不作任何扩展的状况下,Spring 中只有五个。若有忘记请查看:「容器初始化先发五虎」;
对于 @Resource
的处理是经过 CommonAnnotationBeanPostProcessor
来完成的。
对于 @Autowired
的处理是经过 AutowiredAnnotationBeanPostProcessor
来处理的。
对于 @Autowired
注解构造器的方式,获取到被注解元素为 null
则直接返回。完成 populateBean()
的过程。
对于剩下的情形,处理思路一致,都是先获取到被注入的对象,而后将维护对象属性之间的关系。
重点突出一下 getBean()
这里仍是咱们熟悉的 getBean()
...
field.set()
维护对象之间的依赖关系。
源码分析首当其冲的就是方法入口,在对象的包装 BeanWrapper
建立完成以后,populateBean()
来处理对象之间的依赖关系:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) { if (mbd.hasPropertyValues()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { // Skip property population phase for null instance. // 没有任何属性须要填充 return; } } if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; /** * InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation() 方法的应用 * 能够控制程序是否进行属性填充 */ if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } } /** * 取得BeanDefinition 中设置的 Property值, * 这些property来自对BeanDefinition的解析, * 具体的过程能够参看对载入个解析BeanDefinition的分析 * 这里是Spring 内部设置的属性值,通常不会设置 */ PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); /** * 处理自动装配,xml的方式可能会有配置自动装配类型的状况 * 或者经过 setAutowireMode() 的方式设置自动装配的模式 */ int resolvedAutowireMode = mbd.getResolvedAutowireMode(); // Spring 默认 既不是 byType 也不是 byName, 默认是null // 这里之因此作这个判断是由于某种特殊的场景下,会修改到自动注入的模型,因此须要作判断 if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); /** * byName 处理 * 经过反射从当前Bean中获得须要注入的属性名, * 而后使用这个属性名向容器申请与之同名的Bean, * 这样实际又触发了另外一个Bean生成和依赖注入的过程 */ if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // byType 处理 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(); } for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // 经过后置处理器来完成处理 PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.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) { // 对属性进行注入 applyPropertyValues(beanName, mbd, bw, pvs); } } 复制代码
经过源码实现能够看出「自动装配」与「注解注入」的处理是有差异的。其中自动装配时经过属性判断来完成。注解注入是经过「后置处理器」来完成的。
不一样的后置处理器的postProcessProperties()
方法对应的是不一样的处理逻辑。
首先,经过 findAutowiringMetadata()
方法获取被注入的元数据。以上述:「情形一」,为例:
而后,在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()) { // 循环被注入的元素,调用 inject 方法 for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Processing injected element of bean '" + beanName + "': " + element); } // 调用注入方法 element.inject(target, beanName, pvs); } } } 复制代码
在这个方法中首先会检查注入的对象,这里须要指出,在 @Autowired
注解构造器的方式下,最终获得的 elementsToIterate
是空。
对于@Autowired
注解的其余使用方式,最终都会调用 element.inject(target, beanName, pvs);
能够看出,这里区分了注解方法与注解属性这两种方式,在本文中,将以注解 属性的方式为例继续展开分析。
在 AutowiredFieldElement
中类中的最终经过 beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter)
返回注入的对象,而后经过 field.set(bean, value);
的方式来维护对象与属性之间的关系。
接下来将分析 resolveDependency()
方法,经过该方法能够发现,最终调用的是 doResolveDependency()
。看到了 doXXXX()
的方法,就又到了 Spring 惯用的套路了,这里这方法就是真正作事的方式。下面就来看看在 doResolveDependency()
中作了什么事情...
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { Object shortcut = descriptor.resolveShortcut(this); if (shortcut != null) { return shortcut; } /** * 根据类型获取,@Autowired 默认根据type */ Class<?> type = descriptor.getDependencyType(); /** * 支持 @value 注解 */ Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); 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 { /** 经过转换器将Bean的值转换为对应的type类型*/ 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())); } } Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } /** * 根据属性类型找到beanFactory中全部类型匹配的Bean * 返回值的结构为: * key:匹配的BeanName; * value:beanName 对应的实例化后的bean 经过 getBean(beanName)返回 */ Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { /** * 若是 autowire 的 require 属性为true * 找到的匹配项为空 则 抛出异常 */ if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; // 根据类型匹配到的数量大于 1个 if (matchingBeans.size() > 1) { // 肯定自动注入的beanName autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans); } else { 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) { //实例化对象 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); } } 复制代码
分析上述代码,能够发现其中主要作了以下的几件事:
①:获取注入对象的类型;
②:解析过程当中对 @value
注解支持;
③:经过 findAutowireCandidates()
方法,根据属性类型找到 BeanFactory
中全部类型匹配的 Bean
。存放在 Map
中返回。在该方法中,会根据给定的类型获取全部 Bean
的名称做为 Map
中的 key
。
对类型匹配的 Bean
作相应的判断,若是大于 1 个,则经过 determineAutowireCandidate()
方法来肯定注入 Bean
的名称。
@Primary
注解的对象来肯定,若是有则返回;
@Priority
注解的对象,若是有则返回。
若是等于 1 个,在返回 Map
中的 key
就是 beanName
;
经过上述的描述发现 @Autowired
注解属性的方式先经过 byType
的方式获取对应类型的对象;当对应类型的对象大于 1 个时,经过 byName
的方式来肯定。
④:最后 descriptor.resolveCandidate(autowiredBeanName, type, this);
经过 beanFactory.getBean(beanName);
获取注入的对象。
在经过 beanFactory.resolveDependency()
方法得到依赖的对象以后,经过 registerDependentBeans()
方法来维护对象之间的依赖关系。
private void registerDependentBeans(@Nullable String beanName, Set<String> autowiredBeanNames) {
if (beanName != null) { for (String autowiredBeanName : autowiredBeanNames) { if (this.beanFactory != null && this.beanFactory.containsBean(autowiredBeanName)) { this.beanFactory.registerDependentBean(autowiredBeanName, beanName); } if (logger.isTraceEnabled()) { logger.trace("Autowiring by type from bean name '" + beanName + "' to bean named '" + autowiredBeanName + "'"); } } } } 复制代码
上述代码中 for
循环全部 @Autowired
注入的属性的名称。判断容器中包含 BeanName
而后调用 this.beanFactory.registerDependentBean(autowiredBeanName, beanName)
。Spring
经过下述的方法来维护了对象之间的依赖关系。
public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = canonicalName(beanName); /** * dependentBeanMap中存储的是目前已经注册的依赖这个bean的全部bean, * 这里从这个集合中获取目前全部已经注册的依赖beanName的bean集合, * 而后看这个集合中是否包含dependentBeanName,便是否已经注册, * 若是包含则表示已经注册,则直接返回; * 不然,将bean依赖关系添加到两个map缓存即完成注册. */ 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); } } 复制代码
上述的代码中,有两个 Map
。这里首先对这两个 Map
稍加解释:
/** 指定的bean与目前已经注册的依赖这个指定的bean的全部依赖关系的缓存(我依赖的)*/
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); /** 指定bean与目前已经注册的建立这个bean所需依赖的全部bean的依赖关系的缓存(依赖个人) */ private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64); 复制代码
在上述的方法中,就是经过上述两个 Map
维护了对象间依赖与被依赖的关系,详细看下图 当前的
Bean
是 demoServiceTwo
注入的对象是 demoServiceThree
。结合这个能够对上面的 Map
有一个更直观的理解。
最后提醒一点,这两个 Map
中保存容器中全部对象之间的关系,直到容器被销毁的时候删除掉。
前面介绍过,经过 @Autowired
注解构造器的方式,在 populateBean()
方法中,经过后置处理器来处理时,获取到的被注入的元素为空,所以直接返回。也就是说这里并无维护对象之间的依赖关系。可是对象和属性之间的依赖关系,在经过构造器实例化对象的时候已经依赖好了。我本身的理解就是 java
对象和对象属性之间的关系已经有了。
本文主要介绍了 Spring 中对象之间依赖关系的处理流程。经过流程图的方式,粗略的看了一下 @Resource
和 @Autowired
注解处理的过程。
本文详细介绍了 @Autowired
注解属性的处理过程、java
对象与属性关系的维护以及 Spring
对象之间的依赖关系的维护。
简单介绍了 @Autowired
注解构造器的处理构成。
关于 @Resource
注解与 @Autowired
注解方法的处理过程,后面有机会在详细分析。
本文使用 mdnice 排版