Spring 源碼學習筆記(四)容器啓動過程中核心類都做了什麼?

細化容器啓動流程,加入擴展點:

  • 配置是否允許Bean覆蓋、循環依賴:默認屬性 allowBeanDefinitionOverriding 、 allowCircularReferences 都爲 null
  • ConversionService 接口:將前端傳過來的參數和後端的 controller 方法上的參數進行綁定的時候用
  • Bean 繼承:合併父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent
  • FactoryBean 接口:適用於 Bean 的創建過程比較複雜的場景,比如數據庫連接池的創建
  • lookup-method/@Lookup:指定方法注入
  • replaced-method:方法注入覆寫

---------------------------------------------------------

項目啓動通過 ApplicationContext context = new ClassPathXmlApplicationContext(...)  在ClassPath中尋找配置文件,根據配置文件內容來構建ApplicationContext。

除了使用ClassPathXmlApplicationContext之外,可以有還尤其構建 ApplicationContext 的方案可供選擇,下面爲了理解整個構建過程,還是使用ClassPathXmlApplicationContext進行分析。 容器啓動的核心方法是 AbstractApplicationContext 中的refresh()。

其實ApplicationContext就是一個BeanFactory,BeanFactory是Spring裏面最底層的接口,提供了最簡單的容器功能,在bean生命週期的各個階段對bean進行各種管理與接口暴露。下面看一下相關的主要繼承結構:

      // 初始化一個 DefaultListableBeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();

ApplicationContext 繼承自 BeanFactory,但不應該被理解爲 BeanFactory 的實現類,而是說內部持有一個實例化的 BeanFactory (DefaultListableBeanFactory)。那麼爲什麼選擇實例化 DefaultListableBeanFactory?關注一下實現了 BeanFactory 下面一層的所有三個接口的ConfigurableListableBeanFactory 類:

ConfigurableListableBeanFactory 只有一個實現類 DefaultListableBeanFactory,而且實現類 DefaultListableBeanFactory 還通過實現右邊的 AbstractAutowireCapableBeanFactory 通吃了右路。所以結論就是,最底下這個傢伙 DefaultListableBeanFactory 基本上是最牛的 BeanFactory 了,這也是爲什麼這邊會使用這個類來實例化的原因。

下面看一下DefaultListableBeanFactory beanFactory = createBeanFactory()時,DefaultListableBeanFactory存儲了什麼?


	/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	/** List of bean definition names, in registration order. */
	private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

	//手動註冊的 singleton bean
	private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {
 
   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");
 
   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(...);
      }
   }
 
   // old? 還記得 “允許 bean 覆蓋” 這個配置嗎?allowBeanDefinitionOverriding
   BeanDefinition oldBeanDefinition;
 
   // 之後會看到,所有的 Bean 註冊後會放入這個 beanDefinitionMap 中
   oldBeanDefinition = this.beanDefinitionMap.get(beanName);
 
   // 處理重複名稱的 Bean 定義的情況
   if (oldBeanDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {
         // 如果不允許覆蓋的話,拋異常
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription()...
      }
      else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
         // log...用框架定義的 Bean 覆蓋用戶自定義的 Bean 
      }
      else if (!beanDefinition.equals(oldBeanDefinition)) {
         // log...用新的 Bean 覆蓋舊的 Bean
      }
      else {
         // log...用同等的 Bean 覆蓋舊的 Bean,這裏指的是 equals 方法返回 true 的 Bean
      }
      // 覆蓋
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
      // 判斷是否已經有其他的 Bean 開始初始化了.
      // 注意,"註冊Bean" 這個動作結束,Bean 依然還沒有初始化,我們後面會有大篇幅說初始化過程,
      // 在 Spring 容器啓動的最後,會 預初始化 所有的 singleton beans
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
         // 最正常的應該是進到這裏。
 
         // 將 BeanDefinition 放到這個 map 中,這個 map 保存了所有的 BeanDefinition
         this.beanDefinitionMap.put(beanName, beanDefinition);
         // 這是個 ArrayList,所以會按照 bean 配置的順序保存每一個註冊的 Bean 的名字
         this.beanDefinitionNames.add(beanName);
         // 這是個 LinkedHashSet,代表的是手動註冊的 singleton bean,
         // 注意這裏是 remove 方法,到這裏的 Bean 當然不是手動註冊的
         // 手動指的是通過調用以下方法註冊的 bean :
         //     registerSingleton(String beanName, Object singletonObject)
         //         這不是重點,解釋只是爲了不讓大家疑惑。Spring 會在後面"手動"註冊一些 Bean,如 "environment"、"systemProperties" 等 bean
         this.manualSingletonNames.remove(beanName);
      }
      // 這個不重要,在預初始化的時候會用到,不必管它。
      this.frozenBeanDefinitionNames = null;
   }
 
   if (oldBeanDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
}

擴展 配置是否允許Bean覆蓋、循環依賴:

默認情況下,allowBeanDefinitionOverriding 屬性爲 null。如果在同一配置文件中 Bean id 或 name 重複了,會拋錯,但是如果不是同一配置文件中,會發生覆蓋。可是有些時候我們希望在系統啓動的過程中就嚴格杜絕發生 Bean 覆蓋,因爲萬一出現這種情況,會增加我們排查問題的成本。

循環依賴說的是 A 依賴 B,而 B 又依賴 A。或者是 A 依賴 B,B 依賴 C,而 C 卻依賴 A。默認 allowCircularReferences 也是 null。

它們兩個屬性是一起出現的,必然可以在同一個地方一起進行配置。

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>

 

DefaultListableBeanFactory beanFactory = createBeanFactory()後,下一步 prepareBeanFactory(factory) ,對beanFactory內屬性進行設置。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // 設置 BeanFactory 的類加載器,我們知道 BeanFactory 需要加載類,也就需要類加載器,
   // 這裏設置爲當前 ApplicationContext 的類加載器
   beanFactory.setBeanClassLoader(getClassLoader());
   // 設置 BeanExpressionResolver
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   // 
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
 
   // 添加一個 BeanPostProcessor,這個 processor 比較簡單,
   // 實現了 Aware 接口的幾個特殊的 beans 在初始化的時候,這個 processor 負責回調
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
 
   // 下面幾行的意思就是,如果某個 bean 依賴於以下幾個接口的實現類,在自動裝配的時候忽略它們,
   // Spring 會通過其他方式來處理這些依賴。
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
 
   /**
    * 下面幾行就是爲特殊的幾個 bean 賦值,如果有 bean 依賴了以下幾個,會注入這邊相應的值,
    * 之前我們說過,"當前 ApplicationContext 持有一個 BeanFactory",這裏解釋了第一行
    * ApplicationContext 繼承了 ResourceLoader、ApplicationEventPublisher、MessageSource
    * 所以對於這幾個,可以賦值爲 this,注意 this 是一個 ApplicationContext
    * 那這裏怎麼沒看到爲 MessageSource 賦值呢?那是因爲 MessageSource 被註冊成爲了一個普通的 bean
    */
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);
 
   // 這個 BeanPostProcessor 也很簡單,在 bean 實例化後,如果是 ApplicationListener 的子類,
   // 那麼將其添加到 listener 列表中,可以理解成:註冊事件監聽器
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
 
   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   // 這裏涉及到特殊的 bean,名爲:loadTimeWeaver,這不是我們的重點,忽略它
   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 往往很 "智能" 就是因爲它會幫我們默認註冊一些有用的 bean,
    * 我們也可以選擇覆蓋
    */
 
   // 如果沒有定義 "environment" 這個 bean,那麼 Spring 會 "手動" 註冊一個
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   // 如果沒有定義 "systemProperties" 這個 bean,那麼 Spring 會 "手動" 註冊一個
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   // 如果沒有定義 "systemEnvironment" 這個 bean,那麼 Spring 會 "手動" 註冊一個
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}

截止目前, 應該說 BeanFactory 已經創建完成。接下來 postProcessBeanFactory(beanFactory);  實現了 BeanFactoryPostProcessor 接口的 Bean 的初始化,invokeBeanFactoryPostProcessors(beanFactory); 執行了其中的 postProcessBeanFactory(factory) 方法。registerBeanPostProcessors(beanFactory); 實現了 BeanPostProcessor 接口的 Bean 也都完成了初始化。(postProcessBeanFactory、invokeBeanFactoryPostProcessors、registerBeanPostProcessors三個方法不做細化)

下面就是最重要的 finishBeanFactoryInitialization(beanFactory); 初始化(含實例化)階段了, 初始化其他還沒被初始化的 singleton beans 了,我們知道它們是單例的,如果沒有設置懶加載,那麼 Spring 會在接下來初始化所有的 singleton beans

// 初始化剩餘的 singleton beans
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
 
   // 首先,初始化名字爲 conversionService 的 Bean。
   // 最有用的場景就是,它用來將前端傳過來的參數和後端的 controller 方法上的參數進行綁定的時候用。
   // 像前端傳過來的字符串、整數要轉換爲後端的 String、Integer 很容易,但是如果 controller 方法需要的是一個枚舉值,或者是 Date 這些非基礎類型(含基礎類型包裝類)值的時候,我們就可以考慮採用 ConversionService 來進行轉換。
   // 注意了,初始化的動作包裝在 beanFactory.getBean(...) 中,這裏先不說細節,先往下看吧
   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));
   }
 
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
         @Override
         public String resolveStringValue(String strVal) {
            return getEnvironment().resolvePlaceholders(strVal);
         }
      });
   }
 
   // 先初始化 LoadTimeWeaverAware 類型的 Bean
   // 一般用於織入第三方模塊,在 class 文件載入 JVM 的時候動態織入,這裏不展開說
   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);
 
   // 沒什麼別的目的,因爲到這一步的時候,Spring 已經開始預初始化 singleton beans 了,
   // 肯定不希望這個時候還出現 bean 定義解析、加載、註冊。
   beanFactory.freezeConfiguration();
 
   // 開始初始化剩下的
   beanFactory.preInstantiateSingletons();
}

擴展 ConversionService:

最有用的場景就是,它用來將前端傳過來的參數和後端的 controller 方法上的參數進行綁定的時候用。

像前端傳過來的字符串、整數要轉換爲後端的 String、Integer 很容易,但是如果 controller 方法需要的是一個枚舉值,或者是 Date 這些非基礎類型(含基礎類型包裝類)值的時候,我們就可以考慮採用 ConversionService 來進行轉換。

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

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

下面再說一個實現這種轉換很簡單的方式,那就是實現 Converter 接口。來看一個很簡單的例子,這樣比什麼都管用。

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;
        }
    }
}

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

最後一條語句 beanFactory.preInstantiateSingletons(); 又回到 DefaultListableBeanFactory 這個類了。下面按前文梳理的順序取代碼:

@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);
 
   // 觸發所有的非懶加載的 singleton beans 的初始化操作
   for (String beanName : beanNames) {
 
      // 合併父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent
      // 下面進行了擴展補充
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
 
      // 非抽象、非懶加載的 singletons。如果配置了 'abstract = true',那是不需要初始化的
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         // 處理 FactoryBean
         if (isFactoryBean(beanName)) {
            // FactoryBean 的話,在 beanName 前面加上 ‘&’ 符號。再調用 getBean,getBean 方法別急
            final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
            // 判斷當前 FactoryBean 是否是 SmartFactoryBean 的實現,此處忽略,直接跳過
            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,只要調用 getBean(beanName) 這個方法就可以進行初始化了
            getBean(beanName);
         }
      }
   }
 
 
   // 到這裏說明所有的非懶加載的 singleton beans 已經完成了初始化
   // 如果我們定義的 bean 是實現了 SmartInitializingSingleton 接口的,那麼在這裏得到回調,忽略
   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();
         }
      }
   }
}

擴展 Bean 繼承:

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 合併父 Bean 中的配置,注意 <bean id="" class="" parent="" /> 中的 parent

<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 設置了 abstract="true" 所以它不會被實例化,child bean 繼承了 parent bean 的兩個屬性,但是對 name 屬性進行了覆寫。

child bean 會繼承 scope、構造器參數值、屬性值、init-method、destroy-method 等等。

當然,不是說 parent bean 中的 abstract = true 在這裏是必須的,只是說如果加上了以後 Spring 在實例化 singleton beans 的時候會忽略這個 bean。

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

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

 

下面看一下getBean方法,要具備FactoryBean的知識,下面擴展一下。

擴展 FactoryBean:

FactoryBean 適用於 Bean 的創建過程比較複雜的場景,比如數據庫連接池的創建。

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;  }  
}

假設現在需要創建一個 Person 的 Bean,首先需要一個 Car 的實例,這裏假設 Car 的實例創建很麻煩,那麼可以把創建 Car 的複雜過程包裝起來:

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(){ 
      // 這裏假設 Car 的實例化過程非常複雜,反正就不是幾行代碼可以寫完的那種
      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; }
}

看看裝配的時候是怎麼配置的:

<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 其實指定的是一個 FactoryBean,不過配置的時候,我們直接讓配置 Person 的 Bean 直接依賴於這個 FactoryBean 就可以了。中間的過程 Spring 已經封裝好了。 現在還用 xml 配置 Bean 依賴的越來越少了,更多時候,我們可能會採用 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; 
    } 
}

這個時候,其實思路也很簡單,把 MyCarFactoryBean 看成是一個簡單的 Bean 就可以了,不必理會什麼 FactoryBean,它是不是 FactoryBean 和我們沒關係。

回過頭,繼續看getBean——>doGetBean。

@Override
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}
 
// 我們在剖析初始化 Bean 的過程,但是 getBean 方法我們經常是用來從容器中獲取 Bean 用的,注意切換思路,
// 已經初始化過了就從容器中直接返回,否則就先初始化再返回
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException {
   // 獲取一個 “正統的” beanName,處理兩種情況,一個是前面說的 FactoryBean(前面帶 ‘&’),
   // 一個是別名問題,因爲這個方法是 getBean,獲取 Bean 用的,你要是傳一個別名進來,是完全可以的
   final String beanName = transformedBeanName(name);
 
   // 注意跟着這個,這個是返回值
   Object bean; 
 
   // 檢查下是不是已經創建過了
   Object sharedInstance = getSingleton(beanName);
 
   // 這裏說下 args 唄,雖然看上去一點不重要。前面我們一路進來的時候都是 getBean(beanName),
   // 所以 args 其實是 null 的,但是如果 args 不爲空的時候,那麼意味着調用方不是希望獲取 Bean,而是創建 Bean
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("...");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      // 下面這個方法:如果是普通 Bean 的話,直接返回 sharedInstance,
      // 如果是 FactoryBean 的話,返回它創建的那個實例對象
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
 
   else {
      if (isPrototypeCurrentlyInCreation(beanName)) {
         // 當前線程已經創建過了此 beanName 的 prototype 類型的 bean,那麼拋異常
         throw new BeanCurrentlyInCreationException(beanName);
      }
 
      // 檢查一下這個 BeanDefinition 在容器中是否存在
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // 如果當前容器不存在這個 BeanDefinition,試試父容器中有沒有
         String nameToLookup = originalBeanName(name);
         if (args != null) {
            // 返回父容器的查詢結果
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
      }
 
      if (!typeCheckOnly) {
         // typeCheckOnly 爲 false,將當前 beanName 放入一個 alreadyCreated 的 Set 集合中。
         markBeanAsCreated(beanName);
      }
 
      /*
       * 稍稍總結一下:
       * 到這裏的話,要準備創建 Bean 了,對於 singleton 的 Bean 來說,容器中還沒創建過此 Bean;
       * 對於 prototype 的 Bean 來說,本來就是要創建一個新的 Bean。
       */
      try {
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);
 
         // 先初始化依賴的所有 Bean,這個很好理解。
         // 注意,這裏的依賴指的是 depends-on 中定義的依賴
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dep : dependsOn) {
               // 檢查是不是有循環依賴,這裏的循環依賴和我們前面說的循環依賴又不一樣,這裏肯定是不允許出現的,不然要亂套了,讀者想一下就知道了
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               // 註冊一下依賴關係
               registerDependentBean(dep, beanName);
               // 先初始化被依賴項
               getBean(dep);
            }
         }
 
         // 創建 singleton 的實例
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
               @Override
               public Object getObject() throws BeansException {
                  try {
                     // 執行創建 Bean,詳情後面再說
                     return createBean(beanName, mbd, args);
                  }
                  catch (BeansException ex) {
                     destroySingleton(beanName);
                     throw ex;
                  }
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }
 
         // 創建 prototype 的實例
         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               // 執行創建 Bean
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }
 
         // 如果不是 singleton 和 prototype 的話,需要委託給相應的實現類來處理
         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 {
                        // 執行創建 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;
}

下面到了createBean方法

@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);
   }
 
   // 準備方法覆寫,這裏又涉及到一個概念:MethodOverrides,它來自於 bean 定義中的 <lookup-method /> 
   // 和 <replaced-method />,如果讀者感興趣,回到 bean 解析的地方看看對這兩個標籤的解析。
   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }
 
   try {
      // 讓 BeanPostProcessor 在這一步有機會返回代理,而不是 bean 實例,
      // 要徹底瞭解清楚這個,需要去看 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);
   }
   // 重頭戲,創建 bean
   Object beanInstance = doCreateBean(beanName, mbdToUse, args);
   if (logger.isDebugEnabled()) {
      logger.debug("Finished creating instance of bean '" + beanName + "'");
   }
   return beanInstance;
}

擴展 方法注入之lookup-method:

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();
}
<!-- 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 生成字節碼的方式來生成一個子類。我們定義的類不能定義爲 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")//或 @Lookup
    protected abstract Command createCommand();
}

上面的返回值用了 MyCommand,當然,如果 Command 只有一個實現類,那返回值也可以寫 Command 。

擴展 方法注入之replaced-method: 就是替換掉 bean 中的一些方法

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

方法覆寫,注意要實現 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 這個方法要被替換掉 -->
    <replaced-method name="computeValue" replacer="replacementComputeValue">
        <arg-type>String</arg-type>
    </replaced-method>
</bean>
 
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>

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

往裏看 doCreateBean 方法:

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,這裏實例化 Bean,這裏非常關鍵,細節之後再說
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   // 這個就是 Bean 裏面的 我們定義的類 的實例,很多地方我描述成 "bean 實例"
   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,這個我真不展開說了,直接跳過吧,很少用的
            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.
   // 下面這塊代碼是爲了解決循環依賴的問題,前文有說過,可以結合着看
   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 {
      // 這一步也是非常關鍵的,這一步負責屬性裝配,因爲前面的實例只是實例化了,並沒有設值,這裏就是設值
      populateBean(beanName, mbd, instanceWrapper);
      if (exposedObject != null) {
         // 還記得 init-method 嗎?還有 InitializingBean 接口?還有 BeanPostProcessor 接口?
         // 這裏就是處理 bean 初始化完成後的各種回調
         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;
}

到這裏,我們已經分析完了 doCreateBean 方法,總的來說,我們已經說完了整個初始化流程。

接下來我們挑 doCreateBean 中的三個細節出來說說。一個是創建 Bean 實例的 createBeanInstance 方法,一個是依賴注入的 populateBean 方法,還有就是回調方法 initializeBean。本文到此結束,下一文,繼續挖!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章