Spring 注入对象处理过程

其实生活中的坑,都是本身挖的,迷茫也是。愿咱们心里坚决并且不失热爱,期待与你的共同进步。java

依赖关系的处理

  上一篇文章中,经过 createBeanInstance() 方法,最终获得了 BeanWrapper 对象。再获得这个对象以后,在Spring中,对于依赖 关系的处理,是经过 BeanWrapper 来完成的。web

1.自动装配与@Autowired

  这里首先作一个区分,由于在以前的很长一段时间内,我都错误的觉得 @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;  ... } 复制代码

1.1 自动装配

  在 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容器中只能有一个这样的类型,不然就会报错!函数

1.2 使用注解来实现自动装配

  @Autowired 注解,它能够对类成员变量、方法及构造函数进行标注,完成自动装配的工做。Spring是经过 @Autowired 来实现自动装配的。 固然,Spring还支持其余的方式来实现自动装配,如:JSR-330的@Inject注解JSR-250的@Resource注解源码分析

  经过注解的方式来自动装配 Bean 的属性,它容许更细粒度的自动装配,咱们能够选择性的标注某一个属性来对其应用自动装配。post

2.依赖注入

  在这篇文章中,我将详细的分析,在一个对象中经过 @Autowired注入或 @Resource 注入属性的处理过程。这里我仍是采起使用情形,而后画出简要 流程图,最后再是源码分析的方式来介绍本文所要涉及的知识点。flex

2.1 平常开发中注入对象的方式

情形一:经过 @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.2 对象之间依赖关系处理流程

对象之间依赖关系处理流程
对象之间依赖关系处理流程
  1. 上图中描述了前面 2.1 中所介绍的四种情形的处理,其中蓝色线条所表示的是 @Resource注解的处理过程。

  2. 红色线条表示 @Autowired注解的处理过程,与之对应的有拆分红三种子状况

    • AutowiredFieldElement 表示注解属性的状况
    • AutowiredMethodElement 表示注解方法的状况
    • 绿颜色的线条表示注解在构造方法上的状况

  经过上述流程图,我从中找到了如下几点。经过已下几点咱们也能够区分 @Resource@Autowired

  1. 两种注解的处理方式都是经过后置处理器来完成处理的,getBeanPostProcessors() 在咱们不作任何扩展的状况下,Spring 中只有五个。若有忘记请查看:容器初始化先发五虎

  2. 对于 @Resource 的处理是经过 CommonAnnotationBeanPostProcessor 来完成的。

  3. 对于 @Autowired 的处理是经过 AutowiredAnnotationBeanPostProcessor来处理的。 两种注解对应的后置处理器

  4. 对于 @Autowired 注解构造器的方式,获取到被注解元素为 null 则直接返回。完成 populateBean() 的过程。

  5. 对于剩下的情形,处理思路一致,都是先获取到被注入的对象,而后将维护对象属性之间的关系。

  6. 重点突出一下 getBean() 这里仍是咱们熟悉的 getBean()...

  7. field.set() 维护对象之间的依赖关系。

3.源码分析

  源码分析首当其冲的就是方法入口,在对象的包装 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()方法对应的是不一样的处理逻辑。

4. @Autowired 注解属性

4.1 处理过程

  首先,经过 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); @Autowired注解的处理

  能够看出,这里区分了注解方法与注解属性这两种方式,在本文中,将以注解 属性的方式为例继续展开分析。

  在 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的名称。 肯定要注入的Bean

    • 首先根据 @Primary 注解的对象来肯定,若是有则返回;
    • 而后在经过 @Priority 注解的对象,若是有则返回。
  • 若是等于 1 个,在返回 Map 中的 key 就是 beanName

  经过上述的描述发现 @Autowired 注解属性的方式先经过 byType 的方式获取对应类型的对象;当对应类型的对象大于 1 个时,经过 byName 的方式来肯定。

④:最后 descriptor.resolveCandidate(autowiredBeanName, type, this); 经过 beanFactory.getBean(beanName); 获取注入的对象。

4.2 对象之间依赖关系的维护

  在经过 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 维护了对象间依赖与被依赖的关系,详细看下图 对象之间依赖关系的维护   当前的 BeandemoServiceTwo 注入的对象是 demoServiceThree。结合这个能够对上面的 Map 有一个更直观的理解。

  最后提醒一点,这两个 Map 中保存容器中全部对象之间的关系,直到容器被销毁的时候删除掉。

5. @Autowired 注解构造器的处理方式

  前面介绍过,经过 @Autowired 注解构造器的方式,在 populateBean() 方法中,经过后置处理器来处理时,获取到的被注入的元素为空,所以直接返回。也就是说这里并无维护对象之间的依赖关系。可是对象和属性之间的依赖关系,在经过构造器实例化对象的时候已经依赖好了。我本身的理解就是 java 对象和对象属性之间的关系已经有了。

6. 总结

  本文主要介绍了 Spring 中对象之间依赖关系的处理流程。经过流程图的方式,粗略的看了一下 @Resource@Autowired 注解处理的过程。

  本文详细介绍了 @Autowired 注解属性的处理过程、java 对象与属性关系的维护以及 Spring 对象之间的依赖关系的维护。

  简单介绍了 @Autowired 注解构造器的处理构成。

  关于 @Resource 注解与 @Autowired 注解方法的处理过程,后面有机会在详细分析。

本文使用 mdnice 排版

相关文章
相关标签/搜索