Spring IOC 容器源碼分析(二)

從篇章一到這里是一個(gè)分水嶺,前面的內(nèi)容都還算比較簡(jiǎn)單,大家要清楚地知道前面都做了哪些事情。

Bean 容器實(shí)例化完成后

說(shuō)到這里,我們回到 refresh() 方法,我重新貼了一遍代碼,看看我們說(shuō)到哪了。是的,我們才說(shuō)完 obtainFreshBeanFactory() 方法。

考慮到篇幅,這里開(kāi)始大幅縮減掉沒(méi)必要詳細(xì)介紹的部分,大家直接看下面的代碼中的注釋就好了。

@Override
public void refresh() throws BeansException, IllegalStateException {
   // 來(lái)個(gè)鎖,不然 refresh() 還沒(méi)結(jié)束,你又來(lái)個(gè)啟動(dòng)或銷毀容器的操作,那不就亂套了嘛
   synchronized (this.startupShutdownMonitor) {

      // 準(zhǔn)備工作,記錄下容器的啟動(dòng)時(shí)間、標(biāo)記“已啟動(dòng)”狀態(tài)、處理配置文件中的占位符
      prepareRefresh();
     
      // 這步比較關(guān)鍵,這步完成后,配置文件就會(huì)解析成一個(gè)個(gè) Bean 定義,注冊(cè)到 BeanFactory 中,
      // 當(dāng)然,這里說(shuō)的 Bean 還沒(méi)有初始化,只是配置信息都提取出來(lái)了,
      // 注冊(cè)也只是將這些信息都保存到了注冊(cè)中心(說(shuō)到底核心是一個(gè) beanName-> beanDefinition 的 map)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // 設(shè)置 BeanFactory 的類加載器,添加幾個(gè) BeanPostProcessor,手動(dòng)注冊(cè)幾個(gè)特殊的 bean
      // 這塊待會(huì)會(huì)展開(kāi)說(shuō)
      prepareBeanFactory(beanFactory);

      try {
         // 【這里需要知道 BeanFactoryPostProcessor 這個(gè)知識(shí)點(diǎn),Bean 如果實(shí)現(xiàn)了此接口,
         // 那么在容器初始化以后,Spring 會(huì)負(fù)責(zé)調(diào)用里面的 postProcessBeanFactory 方法。】
        
         // 這里是提供給子類的擴(kuò)展點(diǎn),到這里的時(shí)候,所有的 Bean 都加載、注冊(cè)完成了,但是都還沒(méi)有初始化
         // 具體的子類可以在這步的時(shí)候添加一些特殊的 BeanFactoryPostProcessor 的實(shí)現(xiàn)類或做點(diǎn)什么事
         postProcessBeanFactory(beanFactory);
         // 調(diào)用 BeanFactoryPostProcessor 各個(gè)實(shí)現(xiàn)類的 postProcessBeanFactory(factory) 回調(diào)方法
         invokeBeanFactoryPostProcessors(beanFactory);          
         
          

         // 注冊(cè) BeanPostProcessor 的實(shí)現(xiàn)類,注意看和 BeanFactoryPostProcessor 的區(qū)別
         // 此接口兩個(gè)方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 兩個(gè)方法分別在 Bean 初始化之前和初始化之后得到執(zhí)行。這里僅僅是注冊(cè),之后會(huì)看到回調(diào)這兩方法的時(shí)機(jī)
         registerBeanPostProcessors(beanFactory);

         // 初始化當(dāng)前 ApplicationContext 的 MessageSource,國(guó)際化這里就不展開(kāi)說(shuō)了,不然沒(méi)完沒(méi)了了
         initMessageSource();

         // 初始化當(dāng)前 ApplicationContext 的事件廣播器,這里也不展開(kāi)了
         initApplicationEventMulticaster();

         // 從方法名就可以知道,典型的模板方法(鉤子方法),不展開(kāi)說(shuō)
         // 具體的子類可以在這里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
         onRefresh();

         // 注冊(cè)事件監(jiān)聽(tīng)器,監(jiān)聽(tīng)器需要實(shí)現(xiàn) ApplicationListener 接口。這也不是我們的重點(diǎn),過(guò)
         registerListeners();

         // 重點(diǎn),重點(diǎn),重點(diǎn)
         // 初始化所有的 singleton beans
         //(lazy-init 的除外)
         finishBeanFactoryInitialization(beanFactory);

         // 最后,廣播事件,ApplicationContext 初始化完成,不展開(kāi)
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         // 銷毀已經(jīng)初始化的 singleton 的 Beans,以免有些 bean 會(huì)一直占用資源
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // 把異常往外拋
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

準(zhǔn)備 Bean 容器: prepareBeanFactory

之前我們說(shuō)過(guò),Spring 把我們?cè)?xml 配置的 bean 都注冊(cè)以后,會(huì)"手動(dòng)"注冊(cè)一些特殊的 bean。

這里簡(jiǎn)單介紹下 prepareBeanFactory(factory) 方法:

/**
 * Configure the factory's standard context characteristics,
 * such as the context's ClassLoader and post-processors.
 * @param beanFactory the BeanFactory to configure
 */
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // 設(shè)置 BeanFactory 的類加載器,我們知道 BeanFactory 需要加載類,也就需要類加載器,
   // 這里設(shè)置為加載當(dāng)前 ApplicationContext 類的類加載器
   beanFactory.setBeanClassLoader(getClassLoader());
    
   // 設(shè)置 BeanExpressionResolver
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   // 
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // 添加一個(gè) BeanPostProcessor,這個(gè) processor 比較簡(jiǎn)單:
   // 實(shí)現(xiàn)了 Aware 接口的 beans 在初始化的時(shí)候,這個(gè) processor 負(fù)責(zé)回調(diào),
   // 這個(gè)我們很常用,如我們會(huì)為了獲取 ApplicationContext 而 implement ApplicationContextAware
   // 注意:它不僅僅回調(diào) ApplicationContextAware,
   //   還會(huì)負(fù)責(zé)回調(diào) EnvironmentAware、ResourceLoaderAware 等,看下源碼就清楚了
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
  
   // 下面幾行的意思就是,如果某個(gè) bean 依賴于以下幾個(gè)接口的實(shí)現(xiàn)類,在自動(dòng)裝配的時(shí)候忽略它們,
   // Spring 會(huì)通過(guò)其他方式來(lái)處理這些依賴。
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

   /**
    * 下面幾行就是為特殊的幾個(gè) bean 賦值,如果有 bean 依賴了以下幾個(gè),會(huì)注入這邊相應(yīng)的值,
    * 之前我們說(shuō)過(guò),"當(dāng)前 ApplicationContext 持有一個(gè) BeanFactory",這里解釋了第一行
    * ApplicationContext 還繼承了 ResourceLoader、ApplicationEventPublisher、MessageSource
    * 所以對(duì)于這幾個(gè)依賴,可以賦值為 this,注意 this 是一個(gè) ApplicationContext
    * 那這里怎么沒(méi)看到為 MessageSource 賦值呢?那是因?yàn)?MessageSource 被注冊(cè)成為了一個(gè)普通的 bean
    */
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // 這個(gè) BeanPostProcessor 也很簡(jiǎn)單,在 bean 實(shí)例化后,如果是 ApplicationListener 的子類,
   // 那么將其添加到 listener 列表中,可以理解成:注冊(cè) 事件監(jiān)聽(tīng)器
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // 這里涉及到特殊的 bean,名為:loadTimeWeaver,這不是我們的重點(diǎn),忽略它
   // tips: ltw 是 AspectJ 的概念,指的是在運(yùn)行期進(jìn)行織入,這個(gè)和 Spring AOP 不一樣,
   //    感興趣的讀者請(qǐng)參考我寫的關(guān)于 AspectJ 的另一篇文章 https://www.javadoop.com/post/aspectj
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   /**
    * 從下面幾行代碼我們可以知道,Spring 往往很 "智能" 就是因?yàn)樗鼤?huì)幫我們默認(rèn)注冊(cè)一些有用的 bean,
    * 我們也可以選擇覆蓋
    */
  
   // 如果沒(méi)有定義 "environment" 這個(gè) bean,那么 Spring 會(huì) "手動(dòng)" 注冊(cè)一個(gè)
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   // 如果沒(méi)有定義 "systemProperties" 這個(gè) bean,那么 Spring 會(huì) "手動(dòng)" 注冊(cè)一個(gè)
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   // 如果沒(méi)有定義 "systemEnvironment" 這個(gè) bean,那么 Spring 會(huì) "手動(dòng)" 注冊(cè)一個(gè)
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}

在上面這塊代碼中,Spring 對(duì)一些特殊的 bean 進(jìn)行了處理,讀者如果暫時(shí)還不能消化它們也沒(méi)有關(guān)系,慢慢往下看。

初始化所有的 singleton beans

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

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

我們來(lái)總結(jié)一下,到目前為止,應(yīng)該說(shuō) BeanFactory 已經(jīng)創(chuàng)建完成,并且所有的實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的 Bean 都已經(jīng)初始化并且其中的 postProcessBeanFactory(factory) 方法已經(jīng)得到回調(diào)執(zhí)行了。而且 Spring 已經(jīng)“手動(dòng)”注冊(cè)了一些特殊的 Bean,如 ‘environment’、‘systemProperties’ 等。

剩下的就是初始化 singleton beans 了,我們知道它們是單例的,如果沒(méi)有設(shè)置懶加載,那么 Spring 會(huì)在接下來(lái)初始化所有的 singleton beans。

// AbstractApplicationContext.java 834

// 初始化剩余的 singleton beans
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {

   // 首先,初始化名字為 conversionService 的 Bean。本著送佛送到西的精神,我在附錄中簡(jiǎn)單介紹了一下 ConversionService,因?yàn)檫@實(shí)在太實(shí)用了
   // 什么,看代碼這里沒(méi)有初始化 Bean ??!
   // 注意了,初始化的動(dòng)作包裝在 beanFactory.getBean(...) 中,這里先不說(shuō)細(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
   // 之前也說(shuō)過(guò),這是 AspectJ 相關(guān)的內(nèi)容,放心跳過(guò)吧
   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);

   // 沒(méi)什么別的目的,因?yàn)榈竭@一步的時(shí)候,Spring 已經(jīng)開(kāi)始預(yù)初始化 singleton beans 了,
   // 肯定不希望這個(gè)時(shí)候還出現(xiàn) bean 定義解析、加載、注冊(cè)。
   beanFactory.freezeConfiguration();

   // 開(kāi)始初始化
   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);
   }
   // this.beanDefinitionNames 保存了所有的 beanNames
   List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

   // 觸發(fā)所有的非懶加載的 singleton beans 的初始化操作
   for (String beanName : beanNames) {
     
      // 合并父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent,用的不多吧,
      // 考慮到這可能會(huì)影響大家的理解,我在附錄中解釋了一下 "Bean 繼承",不了解的請(qǐng)到附錄中看一下
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
     
      // 非抽象、非懶加載的 singletons。如果配置了 'abstract = true',那是不需要初始化的
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         // 處理 FactoryBean(讀者如果不熟悉 FactoryBean,請(qǐng)移步附錄區(qū)了解)
         if (isFactoryBean(beanName)) {
            // FactoryBean 的話,在 beanName 前面加上 ‘&’ 符號(hào)。再調(diào)用 getBean,getBean 方法別急
            final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
            // 判斷當(dāng)前 FactoryBean 是否是 SmartFactoryBean 的實(shí)現(xiàn),此處忽略,直接跳過(guò)
            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 {
            // 對(duì)于普通的 Bean,只要調(diào)用 getBean(beanName) 這個(gè)方法就可以進(jìn)行初始化了
            getBean(beanName);
         }
      }
   }

  
   // 到這里說(shuō)明所有的非懶加載的 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();
         }
      }
   }
}

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

getBean

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

// AbstractBeanFactory 196

@Override
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}

// 我們?cè)谄饰龀跏蓟?Bean 的過(guò)程,但是 getBean 方法我們經(jīng)常是用來(lái)從容器中獲取 Bean 用的,注意切換思路,
// 已經(jīng)初始化過(guò)了就從容器中直接返回,否則就先初始化再返回
@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è)是前面說(shuō)的 FactoryBean(前面帶 ‘&’),
   // 一個(gè)是別名問(wèn)題,因?yàn)檫@個(gè)方法是 getBean,獲取 Bean 用的,你要是傳一個(gè)別名進(jìn)來(lái),是完全可以的
   final String beanName = transformedBeanName(name);
  
   // 注意跟著這個(gè),這個(gè)是返回值
   Object bean; 

   // 檢查下是不是已經(jīng)創(chuàng)建過(guò)了
   Object sharedInstance = getSingleton(beanName);
  
   // 這里說(shuō)下 args 唄,雖然看上去一點(diǎn)不重要。前面我們一路進(jìn)來(lái)的時(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í)例對(duì)象
      // (FactoryBean 知識(shí),讀者若不清楚請(qǐng)移步附錄)
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else {
      if (isPrototypeCurrentlyInCreation(beanName)) {
         // 創(chuàng)建過(guò)了此 beanName 的 prototype 類型的 bean,那么拋異常,
         // 往往是因?yàn)橄萑肓搜h(huán)引用
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // 檢查一下這個(gè) BeanDefinition 在容器中是否存在
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // 如果當(dāng)前容器不存在這個(gè) BeanDefinition,試試父容器中有沒(méi)有
         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 了,對(duì)于 singleton 的 Bean 來(lái)說(shuō),容器中還沒(méi)創(chuàng)建過(guò)此 Bean;
       * 對(duì)于 prototype 的 Bean 來(lái)說(shuō),本來(lái)就是要?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)依賴和我們前面說(shuō)的循環(huán)依賴又不一樣,這里肯定是不允許出現(xiàn)的,不然要亂套了,讀者想一下就知道了
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               // 注冊(cè)一下依賴關(guān)系
               registerDependentBean(dep, beanName);
               // 先初始化被依賴項(xiàng)
               getBean(dep);
            }
         }

         // 如果是 singleton scope 的,創(chuàng)建 singleton 的實(shí)例
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
               @Override
               public Object getObject() throws BeansException {
                  try {
                     // 執(zhí)行創(chuàng)建 Bean,詳情后面再說(shuō)
                     return createBean(beanName, mbd, args);
                  }
                  catch (BeansException ex) {
                     destroySingleton(beanName);
                     throw ex;
                  }
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }

         // 如果是 prototype scope 的,創(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)類來(lái)處理
         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;
      }
   }

   // 最后,檢查一下類型對(duì)不對(duì),不對(duì)的話就拋異常,對(duì)的話就返回了
   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)該也猜到了,接下來(lái)當(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ù)嘛,不過(guò)要注意,在我們的初始化階段,args 是 null。

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

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

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

以上這種屬于混用了 xml 和 注解 兩種方式的配置方式,Spring 會(huì)處理這種情況。

好了,讀者要知道這么回事就可以了,繼續(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,它來(lái)自于 bean 定義中的 <lookup-method /> 
   // 和 <replaced-method />,如果讀者感興趣,回到 bean 解析的地方看看對(duì)這兩個(gè)標(biāo)簽的解析。
   // 我在附錄中也對(duì)這兩個(gè)標(biāo)簽的相關(guān)知識(shí)點(diǎn)進(jìn)行了介紹,讀者可以移步去看看
   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }

   try {
      // 讓 InstantiationAwareBeanPostProcessor 在這一步有機(jī)會(huì)返回代理,
      // 在 《Spring AOP 源碼分析》那篇文章中有解釋,這里先跳過(guò)
      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

我們繼續(xù)往里看 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) {
      // 說(shuō)明不是 FactoryBean,這里實(shí)例化 Bean,這里非常關(guān)鍵,細(xì)節(jié)之后再說(shuō)
      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;

   // 建議跳過(guò)吧,涉及接口:MergedBeanDefinitionPostProcessor
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
            // MergedBeanDefinitionPostProcessor,這個(gè)我真不展開(kāi)說(shuō)了,直接跳過(guò)吧,很少用的
            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)依賴的問(wèn)題,以后有時(shí)間,我再對(duì)循環(huán)依賴這個(gè)問(wèn)題進(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í)例化了,并沒(méi)有設(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 方法,總的來(lái)說(shuō),我們已經(jīng)說(shuō)完了整個(gè)初始化流程。

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

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

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

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

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
   // 確保已經(jīng)加載了此 class
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   // 校驗(yàn)一下這個(gè)類的訪問(wèn)權(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)  {
      // 采用工廠方法實(shí)例化,不熟悉這個(gè)概念的讀者請(qǐng)看附錄,注意,不是 FactoryBean
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // 如果不是第一次創(chuàng)建,比如第二次創(chuàng)建 prototype bean。
   // 這種情況下,我們可以從第一次創(chuàng)建知道,采用無(wú)參構(gòu)造函數(shù),還是構(gòu)造函數(shù)依賴注入 來(lái)完成實(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 {
         // 無(wú)參構(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)用無(wú)參構(gòu)造函數(shù)
   return instantiateBean(beanName, mbd);
}

挑個(gè)簡(jiǎn)單的無(wú)參構(gòu)造函數(shù)構(gòu)造實(shí)例來(lái)看看:

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() {
               
               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)鍵的地方在于:

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

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

// SimpleInstantiationStrategy 59

@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {

   // 如果不存在方法覆寫,那就使用 java 反射進(jìn)行實(shí)例化,否則使用 CGLIB,
   // 方法覆寫 請(qǐng)參見(jiàn)附錄"方法注入"中對(duì) lookup-method 和 replaced-method 的介紹
   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<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 來(lái)完成實(shí)例化,需要依賴于 CGLIB 生成子類,這里就不展開(kāi)了。
      // tips: 因?yàn)槿绻皇褂?CGLIB 的話,存在 override 的情況 JDK 并沒(méi)有提供相應(yīng)的實(shí)例化支持
      return instantiateWithMethodInjection(bd, beanName, owner);
   }
}

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

bean 屬性注入

看完了 createBeanInstance(...) 方法,我們來(lái)看看 populateBean(...) 方法,該方法負(fù)責(zé)進(jìn)行屬性設(shè)值,處理依賴。

// 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í)例化完成(通過(guò)工廠方法或構(gòu)造方法),但是還沒(méi)開(kāi)始屬性設(shè)值,
   // InstantiationAwareBeanPostProcessor 的實(shí)現(xiàn)類可以在這里對(duì) bean 進(jìn)行狀態(tài)修改,
   // 我也沒(mé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)過(guò)其他的 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);

      // 通過(guò)名字找到所有屬性值,如果是 bean 依賴,先初始化依賴的 bean。記錄依賴關(guān)系
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }

      // 通過(guò)類型裝配。復(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
               // 對(duì)采用 @Autowired、@Value 注解的依賴進(jìn)行設(shè)值,這里的內(nèi)容也是非常豐富的,不過(guò)本文不會(huì)展開(kāi)說(shuō)了,感興趣的讀者請(qǐng)自行研究
               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)了,這塊代碼比較簡(jiǎn)單。

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)沒(méi)有,BeanPostProcessor 的兩個(gè)回調(diào)都發(fā)生在這邊,只不過(guò)中間處理了 init-method,是不是和讀者原來(lái)的認(rèn)知有點(diǎn)不一樣了?

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

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

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