死磕Spring原始碼-依賴注入

w39發表於2021-09-09

我們分析了IOC容器的初始化,可以看出初始化其實就是在IoC容器中建立BeanDefinition資料對映,但並沒有對Bean的依賴關係進行注入,依賴注入是使用者第一次向IoC容器索要Bean的時候觸發的,呼叫BeanFactory的getBean方法將觸發依賴注入,這個時候才會建立物件例項,也可以透過設定bean的lazy-init屬性來讓bean的例項化過程在容器初始化的過程就完成,如果透過設定Bean的lazy-init屬性,那麼在容器初始化這個bean的時候就會呼叫getBean去觸發依賴注入。

如果doGetBean方法在當前的IoC容器中找不到Bean,會到雙親BeanFactory中去取,如果當前的雙親容器找不到那就再順著雙親BeanFactory鏈一直向上尋找。

get某一個Bean的時候會依賴注入其所依賴的所有的Bean,觸發getBean的遞迴呼叫,直到取到一個沒有任何依賴的bean為止。

依賴注入實現過程圖:

圖片描述

依賴注入比較重要的兩個方法:createBeanInstance和populateBean

createBeanInstance例項化Bean物件

圖片描述

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
     // Instantiate the bean.
     BeanWrapper instanceWrapper = null;
     if (mbd.isSingleton()) {
          instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
     }
     if (instanceWrapper == null) {
          instanceWrapper = createBeanInstance(beanName, mbd, args);
     }
     final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
     Class> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

     // Allow post-processors to modify the merged bean definition.
     synchronized (mbd.postProcessingLock) {
          if (!mbd.postProcessed) {
               applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
               mbd.postProcessed = true;
          }
     }

     // Eagerly cache singletons to be able to resolve circular references
     // even when triggered by lifecycle interfaces like BeanFactoryAware.
     boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
               isSingletonCurrentlyInCreation(beanName));
     if (earlySingletonExposure) {
          if (logger.isDebugEnabled()) {
               logger.debug("Eagerly caching bean '" + beanName +
                         "' to allow for resolving potential circular references");
          }
          addSingletonFactory(beanName, new ObjectFactory() {
               @Override
               public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
               }
          });
     }

     // Initialize the bean instance.
     Object exposedObject = bean;
     try {
          populateBean(beanName, mbd, instanceWrapper);
          if (exposedObject != null) {
               exposedObject = initializeBean(beanName, exposedObject, mbd);
          }
     }
     catch (Throwable ex) {
          if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
               throw (BeanCreationException) ex;
          }
          else {
               throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
          }
     }

     if (earlySingletonExposure) {
          Object earlySingletonReference = getSingleton(beanName, false);
          if (earlySingletonReference != null) {
               if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
               }
               else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                         if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                              actualDependentBeans.add(dependentBean);
                         }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                         throw new BeanCurrentlyInCreationException(beanName,
                                   "Bean with name '" + beanName + "' has been injected into other beans [" +
                                   StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                   "] in its raw version as part of a circular reference, but has eventually been " +
                                   "wrapped. This means that said other beans do not use the final version of the " +
                                   "bean. This is often the result of over-eager type matching - consider using " +
                                   "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
               }
          }
     }

     // Register bean as disposable.
     try {
          registerDisposableBeanIfNecessary(beanName, bean, mbd);
     }
     catch (BeanDefinitionValidationException ex) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
     }

     return exposedObject;
}

createBeanInstance中生成了Bean所包含的Java物件,Spring中用SimpleInstantiationStrategy類來生成Bean物件的例項,例項化Java物件的方法有兩種:

1、透過BeanUtils,它使用了JVM的反射功能來生成Java物件例項

2、用CGLIB來生成,CGLIB是一種常用的位元組碼生成器的類庫

@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
     // Don't override the class with CGLIB if no overrides.
     if (bd.getMethodOverrides().isEmpty()) {
          Constructor> constructorToUse;
          synchronized (bd.constructorArgumentLock) {
               constructorToUse = (Constructor>) bd.resolvedConstructorOrFactoryMethod;
               if (constructorToUse == null) {
                    final Class> clazz = bd.getBeanClass();
                    if (clazz.isInterface()) {
                         throw new BeanInstantiationException(clazz, "Specified class is an interface");
                    }
                    try {
                         if (System.getSecurityManager() != null) {
                              constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction>() {
                                   @Override
                                   public Constructor> run() throws Exception {
                                        return clazz.getDeclaredConstructor((Class[]) null);
                                   }
                              });
                         }
                         else {
                              constructorToUse =     clazz.getDeclaredConstructor((Class[]) null);
                         }
                         bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    }
                    catch (Throwable ex) {
                         throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                    }
               }
          }
//透過BeanUtils進行例項化,從這個方法中可以看到具體呼叫了ctor.newInstance()方法
          return BeanUtils.instantiateClass(constructorToUse);
     }
     else {
          // 使用CGLIB來例項化物件
          return instantiateWithMethodInjection(bd, beanName, owner);
     }
}

Bean物件生成好了之後,Spring用BeanWrapper來持有建立出來的Bean物件,接下來Spring透過populateBean方法來把這些Bean物件的依賴關係設定好,以完成整個依賴注入的過程。

依賴注入的發生是在BeanWrapper的setPropertyValues中,具體的實現過程在其子類BeanWrapperImpl;createBeanInstance方法返回值就是一個BeanWrapper物件。再把BeanWrapper物件作為一個形參傳入populateBean中。populateBean是對Bean的初始化,依賴注入就發生在這裡。

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
     //這裡透過解析BeanDefinition來獲取property值
     PropertyValues pvs = mbd.getPropertyValues();

     if (bw == null) {
          if (!pvs.isEmpty()) {
               throw new BeanCreationException(
                         mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
          }
          else {
               // Skip property population phase for null instance.
               return;
          }
     }

     // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
     // state of the bean before properties are set. This can be used, for example,
     // to support styles of field injection.
     boolean continueWithPropertyPopulation = true;

     if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
          for (BeanPostProcessor bp : getBeanPostProcessors()) {
               if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                         continueWithPropertyPopulation = false;
                         break;
                    }
               }
          }
     }

     if (!continueWithPropertyPopulation) {
          return;
     }
          //開始進行依賴注入的過程,先處理autowire的注入,可以根據Bean的名字或型別來完成Bean的autowire
     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
               mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
          MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

          // Add property values based on autowire by name if applicable.
          if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
               autowireByName(beanName, mbd, bw, newPvs);
          }

          // Add property values based on autowire by type if applicable.
          if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
               autowireByType(beanName, mbd, bw, newPvs);
          }

          pvs = newPvs;
     }

     boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
     boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

     if (hasInstAwareBpps || needsDepCheck) {
          PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
          if (hasInstAwareBpps) {
               for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                         pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                         if (pvs == null) {
                              return;
                         }
                    }
               }
          }
          if (needsDepCheck) {
               checkDependencies(beanName, mbd, filteredPds, pvs);
          }
     }
        //對屬性進行注入
     applyPropertyValues(beanName, mbd, bw, pvs);
}

populateBean解析BeanDefinition中設定的property值,獲取到Bean的依賴資訊並設定Bean的依賴關係。透過使用BeanDefinitionResolver對BeanDefinition進行解析,然後注入到property中。
resolveValueIfNecessary方法包含了對所有的注入型別的處理,裡面包含各種instanceof的判斷,比如RuntimeBeanReference,Array,List,Map等資料型別,RuntimeBeanReference是在對BeanDefinition進行解析時生成的資料物件,是在載入BeanDefinition時根據配置生成的,如果RuntimeBeanReference是在雙親容器中則從雙親容器中去獲取Bean(透過getBean方法)。

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
     if (pvs == null || pvs.isEmpty()) {
          return;
     }

     MutablePropertyValues mpvs = null;
     List original;

     if (System.getSecurityManager() != null) {
          if (bw instanceof BeanWrapperImpl) {
               ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
          }
     }

     if (pvs instanceof MutablePropertyValues) {
          mpvs = (MutablePropertyValues) pvs;
          if (mpvs.isConverted()) {
               // Shortcut: use the pre-converted values as-is.
               try {
                    bw.setPropertyValues(mpvs);
                    return;
               }
               catch (BeansException ex) {
                    throw new BeanCreationException(
                              mbd.getResourceDescription(), beanName, "Error setting property values", ex);
               }
          }
          original = mpvs.getPropertyValueList();
     }
     else {
          original = Arrays.asList(pvs.getPropertyValues());
     }

     TypeConverter converter = getCustomTypeConverter();
     if (converter == null) {
          converter = bw;
     }
     BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

     // Create a deep copy, resolving any references for values.
     List deepCopy = new ArrayList(original.size());
     boolean resolveNecessary = false;
     for (PropertyValue pv : original) {
          if (pv.isConverted()) {
               deepCopy.add(pv);
          }
          else {
               String propertyName = pv.getName();
               Object originalValue = pv.getValue();
               Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
               Object convertedValue = resolvedValue;
               boolean convertible = bw.isWritableProperty(propertyName) &&
                         !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
               if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
               }
               // Possibly store converted value in merged bean definition,
               // in order to avoid re-conversion for every created bean instance.
               if (resolvedValue == originalValue) {
                    if (convertible) {
                         pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
               }
               else if (convertible && originalValue instanceof TypedStringValue &&
                         !((TypedStringValue) originalValue).isDynamic() &&
                         !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
               }
               else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
               }
          }
     }
     if (mpvs != null && !resolveNecessary) {
          mpvs.setConverted();
     }

     // Set our (possibly massaged) deep copy.
     try {
          bw.setPropertyValues(new MutablePropertyValues(deepCopy));
     }
     catch (BeansException ex) {
          throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
     }
}

完成解析過程後就已經是為依賴注入做好了準備條件,依賴注入的發生是在BeanWrapper的setPropertyValues中,具體的實現過程在其子類BeanWrapperImpl。

setPropertyValue的方法呼叫棧:

圖片描述

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/854/viewspace-2799156/,如需轉載,請註明出處,否則將追究法律責任。

相關文章