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 排版

相關文章
相關標籤/搜索