Spring IOC 容器源碼分析(2)

轉(zhuǎn)自:https://javadoop.com/post/spring-ioc

初始化所有的 singleton beans

我們的重點(diǎn)當(dāng)然是 finishBeanFactoryInitialization(beanFactory); 這個(gè)巨頭了,這里會負(fù)責(zé)初始化所有的 singleton beans。

注意,后面的描述中,我都會使用初始化或預(yù)初始化來代表這個(gè)階段。主要是 Spring 需要在這個(gè)階段完成所有的 singleton beans 的實(shí)例化。

我們來總結(jié)一下,到目前為止,應(yīng)該說 BeanFactory 已經(jīng)創(chuàng)建完成,并且所有的實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的 Bean 都已經(jīng)初始化并且其中的 postProcessBeanFactory(factory) 方法已經(jīng)得到執(zhí)行了。所有實(shí)現(xiàn)了 BeanPostProcessor 接口的 Bean 也都完成了初始化。

剩下的就是初始化其他還沒被初始化的 singleton beans 了,我們知道它們是單例的,如果沒有設(shè)置懶加載,那么 Spring 會在接下來初始化所有的 singleton beans。

// AbstractApplicationContext.java 834

// 初始化剩余的 singleton beans
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
 
   // 首先,初始化名字為 conversionService 的 Bean。本著送佛送到西的精神,
   // 我在附錄中簡單介紹了一下 ConversionService,因?yàn)檫@實(shí)在太實(shí)用了
   // 什么,看代碼這里沒有初始化 Bean ??!
   // 注意了,初始化的動作包裝在 beanFactory.getBean(...) 中,這里先不說細(xì)節(jié),先往下看吧
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }
 
   // Register a default embedded(嵌入式) value resolver if no bean post-processor
   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
         @Override
         public String resolveStringValue(String strVal) {
            return getEnvironment().resolvePlaceholders(strVal);
         }
      });
   }
 
   // 先初始化 LoadTimeWeaverAware 類型的 Bean
   // 一般用于織入第三方模塊,在 class 文件載入 JVM 的時(shí)候動態(tài)織入,這里不展開說
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }
 
   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);
 
   // 沒什么別的目的,因?yàn)榈竭@一步的時(shí)候,Spring 已經(jīng)開始預(yù)初始化 singleton beans 了,
   // 肯定不希望這個(gè)時(shí)候還出現(xiàn) bean 定義加載、解析、注冊。
   beanFactory.freezeConfiguration();
 
   // 開始初始化剩下的
   beanFactory.preInstantiateSingletons();
}

從上面最后一行往里看,我們又回到 DefaultListableBeanFactory 這個(gè)類了,這個(gè)類大家應(yīng)該都不陌生了吧。

preInstantiateSingletons

// DefaultListableBeanFactory 728

@Override
public void preInstantiateSingletons() throws BeansException {
   if (this.logger.isDebugEnabled()) {
      this.logger.debug("Pre-instantiating singletons in " + this);
   }
 
   List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
 
   // 觸發(fā)所有的非懶加載的 singleton beans 的初始化操作
   for (String beanName : beanNames) {
 
      // 合并父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent,用的不多吧,
      // 考慮到這可能會影響大家的理解,我在附錄中解釋了一下 "Bean 繼承",請移步
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
 
      // 非抽象、非懶加載的 singletons。如果配置了 'abstract = true',那是不需要初始化的
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         // 處理 FactoryBean(讀者如果不熟悉 FactoryBean,請移步附錄區(qū)了解)
         if (isFactoryBean(beanName)) {
            // FactoryBean 的話,在 beanName 前面加上 ‘&’ 符號。再調(diào)用 getBean,getBean 方法別急
            final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
            // 判斷當(dāng)前 FactoryBean 是否是 SmartFactoryBean 的實(shí)現(xiàn),此處忽略,直接跳過
            boolean isEagerInit;
            if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
               isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                  @Override
                  public Boolean run() {
                     return ((SmartFactoryBean<?>) factory).isEagerInit();
                  }
               }, getAccessControlContext());
            }
            else {
               isEagerInit = (factory instanceof SmartFactoryBean &&
                     ((SmartFactoryBean<?>) factory).isEagerInit());
            }
            if (isEagerInit) {
 
               getBean(beanName);
            }
         }
         else {
            // 對于普通的 Bean,只要調(diào)用 getBean(beanName) 這個(gè)方法就可以進(jìn)行初始化了
            getBean(beanName);
         }
      }
   }
 
   // 到這里說明所有的非懶加載的 singleton beans 已經(jīng)完成了初始化
   // 如果我們定義的 bean 是實(shí)現(xiàn)了 SmartInitializingSingleton 接口的,那么在這里得到回調(diào),忽略
   for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
         final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
               @Override
               public Object run() {
                  smartSingleton.afterSingletonsInstantiated();
                  return null;
               }
            }, getAccessControlContext());
         }
         else {
            smartSingleton.afterSingletonsInstantiated();
         }
      }
   }
}

接下來,我們就進(jìn)入到 getBean(beanName) 方法了,這個(gè)方法我們經(jīng)常用來從 BeanFactory 中獲取一個(gè) Bean,而初始化的過程也封裝到了這個(gè)方法里。

getBean

在繼續(xù)前進(jìn)之前,讀者應(yīng)該具備 FactoryBean 的知識,如果讀者還不熟悉,請移步附錄部分了解 FactoryBean。

@Override
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}
 
// 我們在剖析初始化 Bean 的過程,但是 getBean 方法我們經(jīng)常是用來從容器中獲取 Bean 用的,注意切換思路,
// 已經(jīng)初始化過了就從容器中直接返回,否則就先初始化再返回
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException {
   // 獲取一個(gè) “正統(tǒng)的” beanName,處理兩種情況,一個(gè)是前面說的 FactoryBean(前面帶 ‘&’),
   // 一個(gè)是別名問題,因?yàn)檫@個(gè)方法是 getBean,獲取 Bean 用的,你要是傳一個(gè)別名進(jìn)來,是完全可以的
   final String beanName = transformedBeanName(name);
 
   // 注意跟著這個(gè),這個(gè)是返回值
   Object bean; 
 
   // 檢查下是不是已經(jīng)創(chuàng)建過了
   Object sharedInstance = getSingleton(beanName);
 
   // 這里說下 args 唄,雖然看上去一點(diǎn)不重要。前面我們一路進(jìn)來的時(shí)候都是 getBean(beanName),
   // 所以 args 其實(shí)是 null 的,但是如果 args 不為空的時(shí)候,那么意味著調(diào)用方不是希望獲取 Bean,而是創(chuàng)建 Bean
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("...");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      // 下面這個(gè)方法:如果是普通 Bean 的話,直接返回 sharedInstance,
      // 如果是 FactoryBean 的話,返回它創(chuàng)建的那個(gè)實(shí)例對象
      // (FactoryBean 知識,讀者若不清楚請移步附錄)
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
 
   else {
      if (isPrototypeCurrentlyInCreation(beanName)) {
         // 當(dāng)前線程已經(jīng)創(chuàng)建過了此 beanName 的 prototype 類型的 bean,那么拋異常
         throw new BeanCurrentlyInCreationException(beanName);
      }
 
      // 檢查一下這個(gè) BeanDefinition 在容器中是否存在
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // 如果當(dāng)前容器不存在這個(gè) BeanDefinition,試試父容器中有沒有
         String nameToLookup = originalBeanName(name);
         if (args != null) {
            // 返回父容器的查詢結(jié)果
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
      }
 
      if (!typeCheckOnly) {
         // typeCheckOnly 為 false,將當(dāng)前 beanName 放入一個(gè) alreadyCreated 的 Set 集合中。
         markBeanAsCreated(beanName);
      }
 
      /*
       * 稍稍總結(jié)一下:
       * 到這里的話,要準(zhǔn)備創(chuàng)建 Bean 了,對于 singleton 的 Bean 來說,容器中還沒創(chuàng)建過此 Bean;
       * 對于 prototype 的 Bean 來說,本來就是要?jiǎng)?chuàng)建一個(gè)新的 Bean。
       */
      try {
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);
 
         // 先初始化依賴的所有 Bean,這個(gè)很好理解。
         // 注意,這里的依賴指的是 depends-on 中定義的依賴
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dep : dependsOn) {
               // 檢查是不是有循環(huán)依賴,這里的循環(huán)依賴和我們前面說的循環(huán)依賴又不一樣,
               // 這里肯定是不允許出現(xiàn)的,不然要亂套了,讀者想一下就知道了
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               // 注冊一下依賴關(guān)系
               registerDependentBean(dep, beanName);
               // 先初始化被依賴項(xiàng)
               getBean(dep);
            }
         }
 
         // 創(chuàng)建 singleton 的實(shí)例
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
               @Override
               public Object getObject() throws BeansException {
                  try {
                     // 執(zhí)行創(chuàng)建 Bean,詳情后面再說
                     return createBean(beanName, mbd, args);
                  }
                  catch (BeansException ex) {
                     destroySingleton(beanName);
                     throw ex;
                  }
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }
 
         // 創(chuàng)建 prototype 的實(shí)例
         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               // 執(zhí)行創(chuàng)建 Bean
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }
 
         // 如果不是 singleton 和 prototype 的話,需要委托給相應(yīng)的實(shí)現(xiàn)類來處理
         else {
            String scopeName = mbd.getScope();
            final Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
               Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                  @Override
                  public Object getObject() throws BeansException {
                     beforePrototypeCreation(beanName);
                     try {
                        // 執(zhí)行創(chuàng)建 Bean
                        return createBean(beanName, mbd, args);
                     }
                     finally {
                        afterPrototypeCreation(beanName);
                     }
                  }
               });
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new BeanCreationException(beanName,
                     "Scope '" + scopeName + "' is not active for the current thread; consider " +
                     "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                     ex);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }
 
   // 最后,檢查一下類型對不對,不對的話就拋異常,對的話就返回了
   if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
      try {
         return getTypeConverter().convertIfNecessary(bean, requiredType);
      }
      catch (TypeMismatchException ex) {
         if (logger.isDebugEnabled()) {
            logger.debug("Failed to convert bean '" + name + "' to required type '" +
                  ClassUtils.getQualifiedName(requiredType) + "'", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}

大家應(yīng)該也猜到了,接下來當(dāng)然是分析 createBean 方法:

protected abstract Object createBean(String beanName, RootBeanDefinition mbd, 
    Object[] args) throws BeanCreationException;

第三個(gè)參數(shù) args 數(shù)組代表創(chuàng)建實(shí)例需要的參數(shù),不就是給構(gòu)造方法用的參數(shù),或者是工廠 Bean 的參數(shù)嘛,不過要注意,在我們的初始化階段,args 是 null。

這回我們要到一個(gè)新的類了 AbstractAutowireCapableBeanFactory,看類名,AutowireCapable?類名是不是也說明了點(diǎn)問題了。

主要是為了以下場景,采用 @Autowired 注解注入屬性值:

public class MessageServiceImpl implements MessageService {
    @Autowired
    private UserService userService;
 
    public String getMessage() {
        return userService.getMessage();
    }
}
<bean id="messageService" class="com.javadoop.example.MessageServiceImpl" />

好了,讀者要知道這么回事就可以了,繼續(xù)向前。

// AbstractAutowireCapableBeanFactory 447

/**
 * Central method of this class: creates a bean instance,
 * populates the bean instance, applies post-processors, etc.
 * @see #doCreateBean
 */
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating instance of bean '" + beanName + "'");
   }
   RootBeanDefinition mbdToUse = mbd;
 
   // 確保 BeanDefinition 中的 Class 被加載
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }
 
   // 準(zhǔn)備方法覆寫,這里又涉及到一個(gè)概念:MethodOverrides,它來自于 bean 定義中的 <lookup-method /> 
   // 和 <replaced-method />,如果讀者感興趣,回到 bean 解析的地方看看對這兩個(gè)標(biāo)簽的解析。
   // 我在附錄中也對這兩個(gè)標(biāo)簽的相關(guān)知識點(diǎn)進(jìn)行了介紹,讀者可以移步去看看
   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }
 
   try {
      // 讓 BeanPostProcessor 在這一步有機(jī)會返回代理,而不是 bean 實(shí)例,
      // 要徹底了解清楚這個(gè),需要去看 InstantiationAwareBeanPostProcessor 接口,這里就不展開說了
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean; 
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }
   // 重頭戲,創(chuàng)建 bean
   Object beanInstance = doCreateBean(beanName, mbdToUse, args);
   if (logger.isDebugEnabled()) {
      logger.debug("Finished creating instance of bean '" + beanName + "'");
   }
   return beanInstance;
}

創(chuàng)建 Bean

往里看 doCreateBean 這個(gè)方法:

/**
 * Actually create the specified bean. Pre-creation processing has already happened
 * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
 * <p>Differentiates between default bean instantiation, use of a
 * factory method, and autowiring a constructor.
 * @param beanName the name of the bean
 * @param mbd the merged bean definition for the bean
 * @param args explicit arguments to use for constructor or factory method invocation
 * @return a new instance of the bean
 * @throws BeanCreationException if the bean could not be created
 * @see #instantiateBean
 * @see #instantiateUsingFactoryMethod
 * @see #autowireConstructor
 */
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
      throws BeanCreationException {
 
   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      // 說明不是 FactoryBean,這里實(shí)例化 Bean,這里非常關(guān)鍵,細(xì)節(jié)之后再說
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   // 這個(gè)就是 Bean 里面的 我們定義的類 的實(shí)例,很多地方我描述成 "bean 實(shí)例"
   final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
   // 類型
   Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
   mbd.resolvedTargetType = beanType;
 
   // 建議跳過吧,涉及接口:MergedBeanDefinitionPostProcessor
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
            // MergedBeanDefinitionPostProcessor,這個(gè)我真不展開說了,直接跳過吧,很少用的
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Post-processing of merged bean definition failed", ex);
         }
         mbd.postProcessed = true;
      }
   }
 
   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   // 下面這塊代碼是為了解決循環(huán)依賴的問題,以后有時(shí)間,我再對循環(huán)依賴這個(gè)問題進(jìn)行解析吧
   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<Object>() {
         @Override
         public Object getObject() throws BeansException {
            return getEarlyBeanReference(beanName, mbd, bean);
         }
      });
   }
 
   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      // 這一步也是非常關(guān)鍵的,這一步負(fù)責(zé)屬性裝配,因?yàn)榍懊娴膶?shí)例只是實(shí)例化了,并沒有設(shè)值,這里就是設(shè)值
      populateBean(beanName, mbd, instanceWrapper);
      if (exposedObject != null) {
         // 還記得 init-method 嗎?還有 InitializingBean 接口?還有 BeanPostProcessor 接口?
         // 這里就是處理 bean 初始化完成后的各種回調(diào)
         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<String> actualDependentBeans = new LinkedHashSet<String>(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;
}

到這里,我們已經(jīng)分析完了 doCreateBean 方法,總的來說,我們已經(jīng)說完了整個(gè)初始化流程。

接下來我們挑 doCreateBean 中的三個(gè)細(xì)節(jié)出來說說。一個(gè)是創(chuàng)建 Bean 實(shí)例的 createBeanInstance 方法,一個(gè)是依賴注入的 populateBean 方法,還有就是回調(diào)方法 initializeBean。

注意了,接下來的這三個(gè)方法要認(rèn)真說那也是極其復(fù)雜的,很多地方我就點(diǎn)到為止了,感興趣的讀者可以自己往里看,最好就是碰到不懂的,自己寫代碼去調(diào)試它。

創(chuàng)建 Bean 實(shí)例

我們先看看 createBeanInstance 方法。需要說明的是,這個(gè)方法如果每個(gè)分支都分析下去,必然也是極其復(fù)雜冗長的,我們挑重點(diǎn)說。此方法的目的就是實(shí)例化我們指定的類。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
   // 確保已經(jīng)加載了此 class
   Class<?> beanClass = resolveBeanClass(mbd, beanName);
 
   // 校驗(yàn)一下這個(gè)類的訪問權(quán)限
   if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
   }
 
   if (mbd.getFactoryMethodName() != null)  {
      // 采用工廠方法factory-bean,factory-method實(shí)例化,不熟悉這個(gè)概念的讀者請看附錄,注意,不是 FactoryBean
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }
 
   // 如果不是第一次創(chuàng)建,比如第二次創(chuàng)建 prototype bean。
   // 這種情況下,我們可以從第一次創(chuàng)建知道,采用無參構(gòu)造函數(shù),還是構(gòu)造函數(shù)依賴注入 來完成實(shí)例化
   boolean resolved = false;
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   if (resolved) {
      if (autowireNecessary) {
         // 構(gòu)造函數(shù)依賴注入
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         // 無參構(gòu)造函數(shù)
         return instantiateBean(beanName, mbd);
      }
   }
 
   // 判斷是否采用有參構(gòu)造函數(shù)
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
      // 構(gòu)造函數(shù)依賴注入
      return autowireConstructor(beanName, mbd, ctors, args);
   }
 
   // 調(diào)用無參構(gòu)造函數(shù)
   return instantiateBean(beanName, mbd);
}

挑個(gè)簡單的無參構(gòu)造函數(shù)構(gòu)造實(shí)例來看看:

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
   try {
      Object beanInstance;
      final BeanFactory parent = this;
      if (System.getSecurityManager() != null) {
         beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
               // 策略模式,默認(rèn)調(diào)用CglibSubclassingInstantiationStrategy
               return getInstantiationStrategy().instantiate(mbd, beanName, parent);
            }
         }, getAccessControlContext());
      }
      else {
         // 策略模式,實(shí)例化
         beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
      }
      // 包裝一下,返回
      BeanWrapper bw = new BeanWrapperImpl(beanInstance);
      initBeanWrapper(bw);
      return bw;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
   }
}

我們可以看到,關(guān)鍵的地方在于:

// 策略模式,默認(rèn)調(diào)用CglibSubclassingInstantiationStrategy
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

這里會進(jìn)行實(shí)際的實(shí)例化過程,我們進(jìn)去看看:

// SimpleInstantiationStrategy 59

@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
 
   // 如果不存在方法覆寫,那就使用 java 反射進(jìn)行實(shí)例化,否則使用 CGLIB,
   // 方法覆寫 請參見附錄"方法注入"中對 lookup-method 和 replaced-method 的介紹
   if (bd.getMethodOverrides().isEmpty()) {
      Constructor<?> constructorToUse;
      synchronized (bd.constructorArgumentLock) {
        // //獲取構(gòu)造方法或者工廠方法
         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<Constructor<?>>() {
                     @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);
            }
         }
      }
      // 利用構(gòu)造方法進(jìn)行實(shí)例化
      return BeanUtils.instantiateClass(constructorToUse);
   }
   else {
      // 存在方法覆寫,利用 CGLIB 來完成實(shí)例化,需要依賴于 CGLIB 生成子類,這里就不展開了
      return instantiateWithMethodInjection(bd, beanName, owner);
   }
}

到這里,我們就算實(shí)例化完成了。我們開始說怎么進(jìn)行屬性注入。

bean 屬性注入

// AbstractAutowireCapableBeanFactory 1203

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
   // bean 實(shí)例的所有屬性都在這里了
   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;
      }
   }
 
   // 到這步的時(shí)候,bean 實(shí)例化完成(通過工廠方法或構(gòu)造方法),但是還沒開始屬性設(shè)值,
   // InstantiationAwareBeanPostProcessor 的實(shí)現(xiàn)類可以在這里對 bean 進(jìn)行狀態(tài)修改,
   // 我也沒找到有實(shí)際的使用,所以我們暫且忽略這塊吧
   boolean continueWithPropertyPopulation = true;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 如果返回 false,代表不需要進(jìn)行后續(xù)的屬性設(shè)值,也不需要再經(jīng)過其他的 BeanPostProcessor 的處理
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }
 
   if (!continueWithPropertyPopulation) {
      return;
   }
 
   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
 
      // 通過名字找到所有屬性值,如果是 bean 依賴,先初始化依賴的 bean。記錄依賴關(guān)系
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }
 
      // 通過類型裝配。復(fù)雜一些
      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;
               // 這里有個(gè)非常有用的 BeanPostProcessor 進(jìn)到這里: AutowiredAnnotationBeanPostProcessor
               // 對采用 @Autowired、@Value 注解的依賴進(jìn)行設(shè)值,這里的內(nèi)容也是非常豐富的,
               // 不過本文不會展開說了,感興趣的讀者請自行研究
               pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvs == null) {
                  return;
               }
            }
         }
      }
      if (needsDepCheck) {
         checkDependencies(beanName, mbd, filteredPds, pvs);
      }
   }
   // 設(shè)置 bean 實(shí)例的屬性值
   applyPropertyValues(beanName, mbd, bw, pvs);
}
initializeBean

屬性注入完成后,這一步其實(shí)就是處理各種回調(diào)了。

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
         @Override
         public Object run() {
            invokeAwareMethods(beanName, bean);
            return null;
         }
      }, getAccessControlContext());
   }
   else {
      // 如果 bean 實(shí)現(xiàn)了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回調(diào)
      invokeAwareMethods(beanName, bean);
   }
 
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // BeanPostProcessor 的 postProcessBeforeInitialization 回調(diào)
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
 
   try {
      // 處理 bean 中定義的 init-method,
      // 或者如果 bean 實(shí)現(xiàn)了 InitializingBean 接口,調(diào)用 afterPropertiesSet() 方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
 
   if (mbd == null || !mbd.isSynthetic()) {
      // BeanPostProcessor 的 postProcessAfterInitialization 回調(diào)
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

大家發(fā)現(xiàn)沒有,BeanPostProcessor 的兩個(gè)回調(diào)都發(fā)生在這邊,只不過中間處理了 init-method,是不是和讀者原來的認(rèn)知有點(diǎn)不一樣了?

附錄

id 和 name
每個(gè) Bean 在 Spring 容器中都有一個(gè)唯一的名字(beanName)和 0 個(gè)或多個(gè)別名(aliases)。

我們從 Spring 容器中獲取 Bean 的時(shí)候,可以根據(jù) beanName,也可以通過別名。

beanFactory.getBean("beanName or alias");

在配置 <bean /> 的過程中,我們可以配置 id 和 name,看幾個(gè)例子就知道是怎么回事了。

<bean id="messageService" name="m1, m2, m3" 
      class="com.javadoop.example.MessageServiceImpl">

以上配置的結(jié)果就是:beanName 為 messageService,別名有 3 個(gè),分別為 m1、m2、m3。

<bean name="m1, m2, m3" 
    class="com.javadoop.example.MessageServiceImpl">

以上配置的結(jié)果就是:beanName 為 m1,別名有 2 個(gè),分別為 m2、m3。

<bean class="com.javadoop.example.MessageServiceImpl">

beanName 為:com.javadoop.example.MessageServiceImpl#0,
別名 1 個(gè),為: com.javadoop.example.MessageServiceImpl

<bean id="messageService" 
    class="com.javadoop.example.MessageServiceImpl">

以上配置的結(jié)果就是:beanName 為 messageService,沒有別名。

配置是否允許 Bean 覆蓋、是否允許循環(huán)依賴
我們說過,默認(rèn)情況下,allowBeanDefinitionOverriding 屬性為 null。如果在同一配置文件中 Bean id 或 name 重復(fù)了,會拋錯(cuò),但是如果不是同一配置文件中,會發(fā)生覆蓋。

可是有些時(shí)候我們希望在系統(tǒng)啟動的過程中就嚴(yán)格杜絕發(fā)生 Bean 覆蓋,因?yàn)槿f一出現(xiàn)這種情況,會增加我們排查問題的成本。

循環(huán)依賴說的是 A 依賴 B,而 B 又依賴 A?;蛘呤?A 依賴 B,B 依賴 C,而 C 卻依賴 A。默認(rèn) allowCircularReferences 也是 null。

它們兩個(gè)屬性是一起出現(xiàn)的,必然可以在同一個(gè)地方一起進(jìn)行配置。

添加這兩個(gè)屬性的作者 Juergen Hoeller 在這個(gè) jira 的討論中說明了怎么配置這兩個(gè)屬性。

public class NoBeanOverridingContextLoader extends ContextLoader {
 
  @Override
  protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {
    super.customizeContext(servletContext, applicationContext);
    AbstractRefreshableApplicationContext arac = (AbstractRefreshableApplicationContext) applicationContext;
    arac.setAllowBeanDefinitionOverriding(false);
  }
}
public class MyContextLoaderListener extends org.springframework.web.context.ContextLoaderListener {
 
  @Override
  protected ContextLoader createContextLoader() {
    return new NoBeanOverridingContextLoader();
  }
}
<listener>
    <listener-class>com.javadoop.MyContextLoaderListener</listener-class>  
</listener>

如果以上方式不能滿足你的需求,請參考這個(gè)鏈接:解決spring中不同配置文件中存在name或者id相同的bean可能引起的問題

profile
我們可以把不同環(huán)境的配置分別配置到單獨(dú)的文件中,舉個(gè)例子:

<beans profile="development"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xsi:schemaLocation="...">
 
    <jdbc:embedded-database id="dataSource">
        <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
        <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
    </jdbc:embedded-database>
</beans>
<beans profile="production"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">
 
    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>

應(yīng)該不必做過多解釋了吧,看每個(gè)文件第一行的 profile=”"。

當(dāng)然,我們也可以在一個(gè)配置文件中使用:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">
 
    <beans profile="development">
        <jdbc:embedded-database id="dataSource">
            <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
            <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
        </jdbc:embedded-database>
    </beans>
 
    <beans profile="production">
        <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
    </beans>
</beans>

理解起來也很簡單吧。

接下來的問題是,怎么使用特定的 profile 呢?Spring 在啟動的過程中,會去尋找 “spring.profiles.active” 的屬性值,根據(jù)這個(gè)屬性值來的。那怎么配置這個(gè)值呢?

Spring 會在這幾個(gè)地方尋找 spring.profiles.active 的屬性值:操作系統(tǒng)環(huán)境變量、JVM 系統(tǒng)變量、web.xml 中定義的參數(shù)、JNDI。

最簡單的方式莫過于在程序啟動的時(shí)候指定:

-Dspring.profiles.active="profile1,profile2"

profile 可以激活多個(gè)
當(dāng)然,我們也可以通過代碼的形式從 Environment 中設(shè)置 profile:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh(); // 重啟

如果是 Spring Boot 的話更簡單,我們一般會創(chuàng)建 application.properties、application-dev.properties、application-prod.properties 等文件,其中 application.properties 配置各個(gè)環(huán)境通用的配置,application-{profile}.properties 中配置特定環(huán)境的配置,然后在啟動的時(shí)候指定 profile:

java -Dspring.profiles.active=prod -jar JavaDoop.jar

如果是單元測試中使用的話,在測試類中使用 @ActiveProfiles 指定,這里就不展開了。

工廠模式生成 Bean

請讀者注意 factory-bean 和 FactoryBean 的區(qū)別。這節(jié)說的是前者,是說靜態(tài)工廠或?qū)嵗S,而后者是 Spring 中的特殊接口,代表一類特殊的 Bean,附錄的下面一節(jié)會介紹 FactoryBean。

設(shè)計(jì)模式里,工廠方法模式分靜態(tài)工廠和實(shí)例工廠,我們分別看看 Spring 中怎么配置這兩個(gè),來個(gè)代碼示例就什么都清楚了。

靜態(tài)工廠:

bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>
public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}
 
    // 靜態(tài)方法
    public static ClientService createInstance() {
        return clientService;
    }
}

實(shí)例工廠:

<bean id="serviceLocator" class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>
 
<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>
 
<bean id="accountService"
    factory-bean="serviceLocator"
    factory-method="createAccountServiceInstance"/>
public class DefaultServiceLocator {
 
    private static ClientService clientService = new ClientServiceImpl();
 
    private static AccountService accountService = new AccountServiceImpl();
 
    public ClientService createClientServiceInstance() {
        return clientService;
    }
 
    public AccountService createAccountServiceInstance() {
        return accountService;
    }
}

FactoryBean
FactoryBean 適用于 Bean 的創(chuàng)建過程比較復(fù)雜的場景,比如數(shù)據(jù)庫連接池的創(chuàng)建。

public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<T> getObjectType();
    boolean isSingleton();
}
public class Person { 
    private Car car ;
    private void setCar(Car car){ this.car = car;  }  
}

我們假設(shè)現(xiàn)在需要?jiǎng)?chuàng)建一個(gè) Person 的 Bean,首先我們需要一個(gè) Car 的實(shí)例,我們這里假設(shè) Car 的實(shí)例創(chuàng)建很麻煩,那么我們可以把創(chuàng)建 Car 的復(fù)雜過程包裝起來:

public class MyCarFactoryBean implements FactoryBean<Car>{
    private String make; 
    private int year ;
 
    public void setMake(String m){ this.make =m ; }
 
    public void setYear(int y){ this.year = y; }
 
    public Car getObject(){ 
      // 這里我們假設(shè) Car 的實(shí)例化過程非常復(fù)雜,反正就不是幾行代碼可以寫完的那種
      CarBuilder cb = CarBuilder.car();
 
      if(year!=0) cb.setYear(this.year);
      if(StringUtils.hasText(this.make)) cb.setMake( this.make ); 
      return cb.factory(); 
    }
 
    public Class<Car> getObjectType() { return Car.class ; } 
 
    public boolean isSingleton() { return false; }
}

我們看看裝配的時(shí)候是怎么配置的:

<bean class = "com.javadoop.MyCarFactoryBean" id = "car">
  <property name = "make" value ="Honda"/>
  <property name = "year" value ="1984"/>
</bean>
<bean class = "com.javadoop.Person" id = "josh">
  <property name = "car" ref = "car"/>
</bean>

看到不一樣了嗎?id 為 “car” 的 bean 其實(shí)指定的是一個(gè) FactoryBean,不過配置的時(shí)候,我們直接讓配置 Person 的 Bean 直接依賴于這個(gè) FactoryBean 就可以了。中間的過程 Spring 已經(jīng)封裝好了。

說到這里,我們再來點(diǎn)干貨。我們知道,現(xiàn)在還用 xml 配置 Bean 依賴的越來越少了,更多時(shí)候,我們可能會采用 java config 的方式來配置,這里有什么不一樣呢?

@Configuration
public class CarConfiguration { 
 
    @Bean
    public MyCarFactoryBean carFactoryBean(){ 
      MyCarFactoryBean cfb = new MyCarFactoryBean();
      cfb.setMake("Honda");
      cfb.setYear(1984);
      return cfb;
    }
 
    @Bean
    public Person aPerson(){ 
    Person person = new Person();
      // 注意這里的不同
    person.setCar(carFactoryBean().getObject());
    return person; 
    } 
}

這個(gè)時(shí)候,其實(shí)我們的思路也很簡單,把 MyCarFactoryBean 看成是一個(gè)簡單的 Bean 就可以了,不必理會什么 FactoryBean,它是不是 FactoryBean 和我們沒關(guān)系。
這個(gè)時(shí)候,其實(shí)我們的思路也很簡單,把 MyCarFactoryBean 看成是一個(gè)簡單的 Bean 就可以了,不必理會什么 FactoryBean,它是不是 FactoryBean 和我們沒關(guān)系。

初始化 Bean 的回調(diào)
有以下四種方案:

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class AnotherExampleBean implements InitializingBean {
 
    public void afterPropertiesSet() {
        // do some initialization work
    }
}
@Bean(initMethod = "init")
public Foo foo() {
    return new Foo();
}
@PostConstruct
public void init() {
 
}

銷毀 Bean 的回調(diào)

<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class AnotherExampleBean implements DisposableBean {
 
    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}
@Bean(destroyMethod = "cleanup")
public Bar bar() {
    return new Bar();
}
@PreDestroy
public void cleanup() {
 
}

ConversionService
既然文中說到了這個(gè),順便提一下好了。

最有用的場景就是,它用來將前端傳過來的參數(shù)和后端的 controller 方法上的參數(shù)進(jìn)行綁定的時(shí)候用。

像前端傳過來的字符串、整數(shù)要轉(zhuǎn)換為后端的 String、Integer 很容易,但是如果 controller 方法需要的是一個(gè)枚舉值,或者是 Date 這些非基礎(chǔ)類型(含基礎(chǔ)類型包裝類)值的時(shí)候,我們就可以考慮采用 ConversionService 來進(jìn)行轉(zhuǎn)換。

<bean id="conversionService"
  class="org.springframework.context.support.ConversionServiceFactoryBean">
  <property name="converters">
    <list>
      <bean class="com.javadoop.learning.utils.StringToEnumConverterFactory"/>
    </list>
  </property>
</bean>

ConversionService 接口很簡單,所以要自定義一個(gè) convert 的話也很簡單。

下面再說一個(gè)實(shí)現(xiàn)這種轉(zhuǎn)換很簡單的方式,那就是實(shí)現(xiàn) Converter 接口。

來看一個(gè)很簡單的例子,這樣比什么都管用。

public class StringToDateConverter implements Converter<String, Date> {
 
    @Override
    public Date convert(String source) {
        try {
            return DateUtils.parseDate(source, "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "HH:mm:ss", "HH:mm");
        } catch (ParseException e) {
            return null;
        }
    }
}

只要注冊這個(gè) Bean 就可以了。這樣,前端往后端傳的時(shí)間描述字符串就很容易綁定成 Date 類型了,不需要其他任何操作。

Bean 繼承
在初始化 Bean 的地方,我們說過了這個(gè):

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

這里涉及到的就是 <bean parent=”" /> 中的 parent 屬性,我們來看看 Spring 中是用這個(gè)來干什么的。

首先,我們要明白,這里的繼承和 java 語法中的繼承沒有任何關(guān)系,不過思路是相通的。child bean 會繼承 parent bean 的所有配置,也可以覆蓋一些配置,當(dāng)然也可以新增額外的配置。

Spring 中提供了繼承自 AbstractBeanDefinition 的 ChildBeanDefinition 來表示 child bean。

看如下一個(gè)例子:

<bean id="inheritedTestBean" abstract="true" class="org.springframework.beans.TestBean">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>
 
<bean id="inheritsWithDifferentClass" class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBean" init-method="initialize">
 
    <property name="name" value="override"/>
</bean>

parent bean 設(shè)置了 abstract=”true” 所以它不會被實(shí)例化,child bean 繼承了 parent bean 的兩個(gè)屬性,但是對 name 屬性進(jìn)行了覆寫。

child bean 會繼承 scope、構(gòu)造器參數(shù)值、屬性值、init-method、destroy-method 等等。

當(dāng)然,我不是說 parent bean 中的 abstract = true 在這里是必須的,只是說如果加上了以后 Spring 在實(shí)例化 singleton beans 的時(shí)候會忽略這個(gè) bean。

比如下面這個(gè)極端 parent bean,它沒有指定 class,所以毫無疑問,這個(gè) bean 的作用就是用來充當(dāng)模板用的 parent bean,此處就必須加上 abstract = true。

<bean id="inheritedTestBeanWithoutClass" abstract="true">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

方法注入
一般來說,我們的應(yīng)用中大多數(shù)的 Bean 都是 singleton 的。singleton 依賴 singleton,或者 prototype 依賴 prototype 都很好解決,直接設(shè)置屬性依賴就可以了。

但是,如果是 singleton 依賴 prototype 呢?這個(gè)時(shí)候不能用屬性依賴,因?yàn)槿绻脤傩砸蕾嚨脑?,我們每次其?shí)拿到的還是第一次初始化時(shí)候的 bean。

一種解決方案就是不要用屬性依賴,每次獲取依賴的 bean 的時(shí)候從 BeanFactory 中取。這個(gè)也是大家最常用的方式了吧。怎么取,我就不介紹了,大部分 Spring 項(xiàng)目大家都會定義那么個(gè)工具類的。

另一種解決方案就是這里要介紹的通過使用 Lookup method。

lookup-method
我們來看一下 Spring Reference 中提供的一個(gè)例子:

package fiona.apple;
 
// no more Spring imports!
 
public abstract class CommandManager {
 
    public Object process(Object commandState) {
        // grab a new instance of the appropriate Command interface
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }
 
    // okay... but where is the implementation of this method?
    protected abstract Command createCommand();
}

xml 配置 <lookup-method />:

<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
    <!-- inject dependencies here as required -->
</bean>
 
<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
    <lookup-method name="createCommand" bean="myCommand"/>
</bean>

Spring 采用 CGLIB 生成字節(jié)碼的方式來生成一個(gè)子類。我們定義的類不能定義為 final class,抽象方法上也不能加 final。

lookup-method 上的配置也可以采用注解來完成,這樣就可以不用配置 <lookup-method /> 了,其他不變:

public abstract class CommandManager {
 
    public Object process(Object commandState) {
        MyCommand command = createCommand();
        command.setState(commandState);
        return command.execute();
    }
 
    @Lookup("myCommand")
    protected abstract Command createCommand();
}

注意,既然用了注解,要配置注解掃描:<context:component-scan base-package=”com.javadoop” />
甚至,我們可以像下面這樣:

public abstract class CommandManager {
 
    public Object process(Object commandState) {
        MyCommand command = createCommand();
        command.setState(commandState);
        return command.execute();
    }
 
    @Lookup
    protected abstract MyCommand createCommand();
}

上面的返回值用了 MyCommand,當(dāng)然,如果 Command 只有一個(gè)實(shí)現(xiàn)類,那返回值也可以寫 Command。

replaced-method
記住它的功能,就是替換掉 bean 中的一些方法。

public class MyValueCalculator {
 
    public String computeValue(String input) {
        // some real code...
    }
 
    // some other methods...
}

方法覆寫,注意要實(shí)現(xiàn) MethodReplacer 接口:

public class ReplacementComputeValue implements org.springframework.beans.factory.support.MethodReplacer {
 
    public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
        // get the input value, work with it, and return a computed result
        String input = (String) args[0];
        ...
        return ...;
    }
}

配置也很簡單:

<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
    <!-- 定義 computeValue 這個(gè)方法要被替換掉 -->
    <replaced-method name="computeValue" replacer="replacementComputeValue">
        <arg-type>String</arg-type>
    </replaced-method>
</bean>
 
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>

arg-type 明顯不是必須的,除非存在方法重載,這樣必須通過參數(shù)類型列表來判斷這里要覆蓋哪個(gè)方法。

BeanPostProcessor
應(yīng)該說 BeanPostProcessor 概念在 Spring 中也是比較重要的。我們看下接口定義:

public interface BeanPostProcessor {
 
   Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
 
   Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
 
}

看這個(gè)接口中的兩個(gè)方法名字我們大體上可以猜測 bean 在初始化之前會執(zhí)行 postProcessBeforeInitialization 這個(gè)方法,初始化完成之后會執(zhí)行 postProcessAfterInitialization 這個(gè)方法。但是,這么理解是非常片面的。

首先,我們要明白,除了我們自己定義的 BeanPostProcessor 實(shí)現(xiàn)外,Spring 容器在啟動時(shí)自動給我們也加了幾個(gè)。如在獲取 BeanFactory 的 obtainFactory() 方法結(jié)束后的 prepareBeanFactory(factory),大家仔細(xì)看會發(fā)現(xiàn),Spring 往容器中添加了這兩個(gè) BeanPostProcessor:ApplicationContextAwareProcessor、ApplicationListenerDetector。

我們回到這個(gè)接口本身,讀者請看第一個(gè)方法,這個(gè)方法接受的第一個(gè)參數(shù)是 bean 實(shí)例,第二個(gè)參數(shù)是 bean 的名字,重點(diǎn)在返回值將會作為新的 bean 實(shí)例,所以,沒事的話這里不能隨便返回個(gè) null。

那意味著什么呢?我們很容易想到的就是,我們這里可以對一些我們想要修飾的 bean 實(shí)例做一些事情。但是對于 Spring 框架來說,它會決定是不是要在這個(gè)方法中返回 bean 實(shí)例的代理,這樣就有更大的想象空間了。

最后,我們說說如果我們自己定義一個(gè) bean 實(shí)現(xiàn) BeanPostProcessor 的話,它的執(zhí)行時(shí)機(jī)是什么時(shí)候?

如果仔細(xì)看了代碼分析的話,其實(shí)很容易知道了,在 bean 實(shí)例化完成、屬性注入完成之后,會執(zhí)行回調(diào)方法,具體請參見類 AbstractAutowireCapableBeanFactory#initBean 方法。

首先會回調(diào)幾個(gè)實(shí)現(xiàn)了 Aware 接口的 bean,然后就開始回調(diào) BeanPostProcessor 的 postProcessBeforeInitialization 方法,之后是回調(diào) init-method,然后再回調(diào) BeanPostProcessor 的 postProcessAfterInitialization 方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容