從Dubbo啟動看Dubbo和Spring的關係

?醬發表於2019-01-13

Spring啟動過程寫的過於冗雜,如果對於這部分不感興趣可以直接跳到Dubbo和Spring的關係,依然能夠愉快的閱讀。

Spring啟動過程

第一步:

ClassPathXmlApplicationContext的構造方法:

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
  private Resource[] configResources;
 
  // 如果已經有 ApplicationContext 並需要配置成父子關係,那麼呼叫這個構造方法
  public ClassPathXmlApplicationContext(ApplicationContext parent) {
    super(parent);
  }
  ...
  public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {
 
    super(parent);
    // 根據提供的路徑,處理成配置檔案陣列(以分號、逗號、空格、tab、換行符分割)
    setConfigLocations(configLocations);
    if (refresh) {
      refresh(); // 核心方法
    }
  }
    ...
}
複製程式碼

接下來,就是refresh(),將原來的ApplicationContext銷燬,然後重新執行一次初始化操作。

@Override
public void refresh() throws BeansException, IllegalStateException {
   // 來個鎖,不然 refresh() 還沒結束,你又來個啟動或銷燬容器的操作,那不就亂套了嘛
   synchronized (this.startupShutdownMonitor) {
 
      // 準備工作,記錄下容器的啟動時間、標記“已啟動”狀態、處理配置檔案中的佔位符
      prepareRefresh();
 
      // 這步比較關鍵,這步完成後,配置檔案就會解析成一個個 Bean 定義,註冊到 BeanFactory 中,
      // 當然,這裡說的 Bean 還沒有初始化,只是配置資訊都提取出來了,
      // 註冊也只是將這些資訊都儲存到了註冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 
      // 設定 BeanFactory 的類載入器,新增幾個 BeanPostProcessor,手動註冊幾個特殊的 bean
      // 這塊待會會展開說
      prepareBeanFactory(beanFactory);
 
      try {
         // 【這裡需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實現了此介面,
         // 那麼在容器初始化以後,Spring 會負責呼叫裡面的 postProcessBeanFactory 方法。】
 
         // 這裡是提供給子類的擴充套件點,到這裡的時候,所有的 Bean 都載入、註冊完成了,但是都還沒有初始化
         // 具體的子類可以在這步的時候新增一些特殊的 BeanFactoryPostProcessor 的實現類或做點什麼事
         postProcessBeanFactory(beanFactory);
         // 呼叫 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);
 
         // 註冊 BeanPostProcessor 的實現類,注意看和 BeanFactoryPostProcessor 的區別
         // 此介面兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 兩個方法分別在 Bean 初始化之前和初始化之後得到執行。注意,到這裡 Bean 還沒初始化
         registerBeanPostProcessors(beanFactory);
 
         // 初始化當前 ApplicationContext 的 MessageSource,國際化這裡就不展開說了,不然沒完沒了了
         initMessageSource();
 
         // 初始化當前 ApplicationContext 的事件廣播器,這裡也不展開了
         initApplicationEventMulticaster();
 
         // 從方法名就可以知道,典型的模板方法(鉤子方法),
         // 具體的子類可以在這裡初始化一些特殊的 Bean(在初始化 singleton beans 之前)
         onRefresh();
 
         // 註冊事件監聽器,監聽器需要實現 ApplicationListener 介面。這也不是我們的重點,過
         registerListeners();
 
         // 重點,重點,重點
         // 初始化所有的 singleton beans
         //(lazy-init 的除外)
         finishBeanFactoryInitialization(beanFactory);
 
         // 最後,廣播事件,ApplicationContext 初始化完成
         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.
         // 銷燬已經初始化的 singleton 的 Beans,以免有些 bean 會一直佔用資源
         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();
      }
   }
}
複製程式碼

建立Bean容器前的準備工作:

protected void prepareRefresh() {
   // 記錄啟動時間,
   // 將 active 屬性設定為 true,closed 屬性設定為 false,它們都是 AtomicBoolean 型別
   this.startupDate = System.currentTimeMillis();
   this.closed.set(false);
   this.active.set(true);
 
   if (logger.isInfoEnabled()) {
      logger.info("Refreshing " + this);
   }
 
   // Initialize any placeholder property sources in the context environment
   initPropertySources();
 
   // 校驗 xml 配置檔案
   getEnvironment().validateRequiredProperties();
 
   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
複製程式碼

建立Bean容器,載入並註冊Bean

這裡會初始化BeanFactory、載入Bean、註冊Bean等等。

AbstractApplicationContext.java

 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
     //關閉就得BeanFactory,建立新的BeanFactory,載入Bean定義、註冊Bean等等。
        this.refreshBeanFactory();
     //返回剛剛建立的BeanFactory
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
        }

        return beanFactory;
    }
複製程式碼

AbstractRefreshableApplicationContext.java 120

@Override
protected final void refreshBeanFactory() throws BeansException {
   // 如果 ApplicationContext 中已經載入過 BeanFactory 了,銷燬所有 Bean,關閉 BeanFactory
   // 注意,應用中 BeanFactory 本來就是可以多個的,這裡可不是說應用全域性是否有 BeanFactory,而是當前
   // ApplicationContext 是否有 BeanFactory
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      // 初始化一個 DefaultListableBeanFactory,為什麼用這個,我們馬上說。
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      // 用於 BeanFactory 的序列化,我想不部分人應該都用不到
      beanFactory.setSerializationId(getId());
 
      // 下面這兩個方法很重要,別跟丟了,具體細節之後說
      // 設定 BeanFactory 的兩個配置屬性:是否允許 Bean 覆蓋、是否允許迴圈引用
      customizeBeanFactory(beanFactory);
 
      // 載入 Bean 到 BeanFactory 中
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}
複製程式碼

customizeBeanFactory(beanFactory)

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
   if (this.allowBeanDefinitionOverriding != null) {
      // 是否允許 Bean 定義覆蓋
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   if (this.allowCircularReferences != null) {
      // 是否允許 Bean 間的迴圈依賴
      beanFactory.setAllowCircularReferences(this.allowCircularReferences);
   }
}
複製程式碼

AbstractXmlApplicationContext.java 80 loadBeanDefinitions(beanFactory)

    /** 我們可以看到,此方法將通過一個 XmlBeanDefinitionReader 例項來載入各個 Bean。*/
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
       // 給這個 BeanFactory 例項化一個 XmlBeanDefinitionReader
       XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
     
       // Configure the bean definition reader with this context's
       // resource loading environment.
       beanDefinitionReader.setEnvironment(this.getEnvironment());
       beanDefinitionReader.setResourceLoader(this);
       beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
     
       // 初始化 BeanDefinitionReader,其實這個是提供給子類覆寫的,
       // 我看了一下,沒有類覆寫這個方法,我們姑且當做不重要吧
       initBeanDefinitionReader(beanDefinitionReader);
       // 重點來了,繼續往下
       loadBeanDefinitions(beanDefinitionReader);
    }
複製程式碼

現在還在這個類中,接下來用剛剛初始化的 Reader 開始來載入 xml 配置,這塊程式碼讀者可以選擇性跳過,不是很重要。也就是說,下面這個程式碼塊,讀者可以很輕鬆地略過。

// AbstractXmlApplicationContext.java 120

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      // 往下看
      reader.loadBeanDefinitions(configResources);
   }
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
   }
}
 
// 上面雖然有兩個分支,不過第二個分支很快通過解析路徑轉換為 Resource 以後也會進到這裡
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
   Assert.notNull(resources, "Resource array must not be null");
   int counter = 0;
   // 注意這裡是個 for 迴圈,也就是每個檔案是一個 resource
   for (Resource resource : resources) {
      // 繼續往下看
      counter += loadBeanDefinitions(resource);
   }
   return counter;
}
 
// XmlBeanDefinitionReader 303
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   return loadBeanDefinitions(new EncodedResource(resource));
}
 
// XmlBeanDefinitionReader 314
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
   Assert.notNull(encodedResource, "EncodedResource must not be null");
   if (logger.isInfoEnabled()) {
      logger.info("Loading XML bean definitions from " + encodedResource.getResource());
   }
   // 用一個 ThreadLocal 來存放所有的配置檔案資源
   Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
   if (currentResources == null) {
      currentResources = new HashSet<EncodedResource>(4);
      this.resourcesCurrentlyBeingLoaded.set(currentResources);
   }
   if (!currentResources.add(encodedResource)) {
      throw new BeanDefinitionStoreException(
            "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
   }
   try {
      InputStream inputStream = encodedResource.getResource().getInputStream();
      try {
         InputSource inputSource = new InputSource(inputStream);
         if (encodedResource.getEncoding() != null) {
            inputSource.setEncoding(encodedResource.getEncoding());
         }
         // 核心部分
         return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
      }
      finally {
         inputStream.close();
      }
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException(
            "IOException parsing XML document from " + encodedResource.getResource(), ex);
   }
   finally {
      currentResources.remove(encodedResource);
      if (currentResources.isEmpty()) {
         this.resourcesCurrentlyBeingLoaded.remove();
      }
   }
}
 
// 還在這個檔案中,第 388 行
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {
   try {
      // 這裡就不看了
      Document doc = doLoadDocument(inputSource, resource);
      // 繼續
      return registerBeanDefinitions(doc, resource);
   }
   catch (...
}
// 還在這個檔案中,第 505 行
// 返回從當前配置檔案載入了多少數量的 Bean
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   int countBefore = getRegistry().getBeanDefinitionCount();
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   return getRegistry().getBeanDefinitionCount() - countBefore;
}
// DefaultBeanDefinitionDocumentReader 90
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   logger.debug("Loading bean definitions");
   Element root = doc.getDocumentElement();
   doRegisterBeanDefinitions(root);
}
複製程式碼

經過漫長的鏈路,一個配置檔案終於轉換為一顆DOM樹了,注意,這裡指的是其中一個配置檔案,不是所有。下面從根節點開始解析:

doRegisterBeanDefinitions:

// DefaultBeanDefinitionDocumentReader 116
protected void doRegisterBeanDefinitions(Element root) {
   // 我們看名字就知道,BeanDefinitionParserDelegate 必定是一個重要的類,它負責解析 Bean 定義,
   // 這裡為什麼要定義一個 parent? 看到後面就知道了,是遞迴問題,
   // 因為 <beans /> 內部是可以定義 <beans /> 的,所以這個方法的 root 其實不一定就是 xml 的根節點,也可以是巢狀在裡面的 <beans /> 節點,從原始碼分析的角度,我們當做根節點就好了
   BeanDefinitionParserDelegate parent = this.delegate;
   this.delegate = createDelegate(getReaderContext(), root, parent);
 
   if (this.delegate.isDefaultNamespace(root)) {
      // 這塊說的是根節點 <beans ... profile="dev" /> 中的 profile 是否是當前環境需要的,
      // 如果當前環境配置的 profile 不包含此 profile,那就直接 return 了,不對此 <beans /> 解析
      // 不熟悉 profile 為何物,不熟悉怎麼配置 profile 讀者的請移步附錄區
      String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
      if (StringUtils.hasText(profileSpec)) {
         String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
               profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
         if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
            if (logger.isInfoEnabled()) {
               logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                     "] not matching: " + getReaderContext().getResource());
            }
            return;
         }
      }
   }
 
   preProcessXml(root); // 鉤子
   parseBeanDefinitions(root, this.delegate);
   postProcessXml(root); // 鉤子
 
   this.delegate = parent;
}
複製程式碼

接下來,看核心解析方法parseBeanDefinitions(roo,this.delegate):

// default namespace 涉及到的就四個標籤 <import />、<alias />、<bean /> 和 <beans />,
// 其他的屬於 custom 的
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               parseDefaultElement(ele, delegate);
            }
            else {
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}
複製程式碼

從上面的程式碼,我們可以看到,對於每個配置來說,分別進入到 parseDefaultElement(ele, delegate); 和 delegate.parseCustomElement(ele); 這兩個分支了。

parseDefaultElement(ele, delegate) 代表解析的節點是 <import /><alias /><bean /><beans /> 這幾個。

這裡的四個標籤之所以是 default 的,是因為它們是處於這個 namespace 下定義的:

http://www.springframework.org/schema/beans
複製程式碼

回過神來,看看處理 default 標籤的方法:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      // 處理 <import /> 標籤
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      // 處理 <alias /> 標籤定義
      // <alias name="fromName" alias="toName"/>
      processAliasRegistration(ele);
   }
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      // 處理 <bean /> 標籤定義,這也算是我們的重點吧
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // 如果碰到的是巢狀的 <beans /> 標籤,需要遞迴
      doRegisterBeanDefinitions(ele);
   }
}
複製程式碼

如果每個標籤都說,那我不吐血,你們都要吐血了。我們挑我們的重點 <bean /> 標籤出來說。

processBeanDefinition

下面是 processBeanDefinition 解析 <bean /> 標籤:

// DefaultBeanDefinitionDocumentReader 298

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   // 將 <bean /> 節點中的資訊提取出來,然後封裝到一個 BeanDefinitionHolder 中,細節往下看
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
 
   // 下面的幾行先不要看,跳過先,跳過先,跳過先,後面會繼續說的
 
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}
複製程式碼

繼續往下看怎麼解析之前,我們先看下 標籤中可以定義哪些屬性:

Property
class 類的全限定名
name 可指定 id、name(用逗號、分號、空格分隔)
scope 作用域
constructor arguments 指定構造引數
properties 設定屬性的值
autowiring mode no(預設值)、byName、byType、 constructor
lazy-initialization mode 是否懶載入(如果被非懶載入的bean依賴了那麼其實也就不能懶載入了)
initialization method bean 屬性設定完成後,會呼叫這個方法
destruction method bean 銷燬後的回撥方法

上面表格中的內容我想大家都非常熟悉吧,如果不熟悉,那就是你不夠了解 Spring 的配置了。

簡單地說就是像下面這樣子:

<bean id="exampleBean" name="name1, name2, name3" class="com.javadoop.ExampleBean"
      scope="singleton" lazy-init="true" init-method="init" destroy-method="cleanup">
 
    <!-- 可以用下面三種形式指定構造引數 -->
  <constructor-arg type="int" value="7500000"/>
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg index="0" value="7500000"/>
 
    <!-- property 的幾種情況 -->
    <property name="beanOne">
        <ref bean="anotherExampleBean"/>
    </property>
    <property name="beanTwo" ref="yetAnotherBean"/>
    <property name="integerProperty" value="1"/>
</bean>
複製程式碼

當然,除了上面舉例出來的這些,還有 factory-bean、factory-method、<lockup-method /><replaced-method /><meta /><qualifier /> 這幾個,大家是不是熟悉呢?

有了以上這些知識以後,我們再繼續往裡看怎麼解析 bean 元素,是怎麼轉換到 BeanDefinitionHolder 的。

// BeanDefinitionParserDelegate 428

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}
 
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
   String id = ele.getAttribute(ID_ATTRIBUTE);
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
 
   List<String> aliases = new ArrayList<String>();
 
   // 將 name 屬性的定義按照 ”逗號、分號、空格“ 切分,形成一個別名列表陣列,
   // 當然,如果你不定義的話,就是空的了
   // 我在附錄中簡單介紹了一下 id 和 name 的配置,大家可以看一眼,有個20秒就可以了
   if (StringUtils.hasLength(nameAttr)) {
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
   }
 
   String beanName = id;
   // 如果沒有指定id, 那麼用別名列表的第一個名字作為beanName
   if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
      if (logger.isDebugEnabled()) {
         logger.debug("No XML 'id' specified - using '" + beanName +
               "' as bean name and " + aliases + " as aliases");
      }
   }
 
   if (containingBean == null) {
      checkNameUniqueness(beanName, aliases, ele);
   }
 
   // 根據 <bean ...>...</bean> 中的配置建立 BeanDefinition,然後把配置中的資訊都設定到例項中,
   // 細節後面再說
   AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
 
   // 到這裡,整個 <bean /> 標籤就算解析結束了,一個 BeanDefinition 就形成了。
   if (beanDefinition != null) {
      // 如果都沒有設定 id 和 name,那麼此時的 beanName 就會為 null,進入下面這塊程式碼產生
      // 如果讀者不感興趣的話,我覺得不需要關心這塊程式碼,對本文原始碼分析來說,這些東西不重要
      if (!StringUtils.hasText(beanName)) {
         try {
            if (containingBean != null) {// 按照我們的思路,這裡 containingBean 是 null 的
               beanName = BeanDefinitionReaderUtils.generateBeanName(
                     beanDefinition, this.readerContext.getRegistry(), true);
            }
            else {
               // 如果我們不定義 id 和 name,那麼我們引言裡的那個例子:
               //   1. beanName 為:com.javadoop.example.MessageServiceImpl#0
               //   2. beanClassName 為:com.javadoop.example.MessageServiceImpl
 
               beanName = this.readerContext.generateBeanName(beanDefinition);
 
               String beanClassName = beanDefinition.getBeanClassName();
               if (beanClassName != null &&
                     beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                     !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                  // 把 beanClassName 設定為 Bean 的別名
                  aliases.add(beanClassName);
               }
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Neither XML 'id' nor 'name' specified - " +
                     "using generated bean name [" + beanName + "]");
            }
         }
         catch (Exception ex) {
            error(ex.getMessage(), ele);
            return null;
         }
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      // 返回 BeanDefinitionHolder
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }
 
   return null;
}
複製程式碼

看看怎麼根據配置建立 BeanDefinition:

public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, BeanDefinition containingBean) {
 
   this.parseState.push(new BeanEntry(beanName));
 
   String className = null;
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
   }
 
   try {
      String parent = null;
      if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
         parent = ele.getAttribute(PARENT_ATTRIBUTE);
      }
      // 建立 BeanDefinition,然後設定類資訊而已,很簡單,就不貼程式碼了
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);
 
      // 設定 BeanDefinition 的一堆屬性,這些屬性定義在 AbstractBeanDefinition 中
      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
 
      /**
       * 下面的一堆是解析 <bean>......</bean> 內部的子元素,
       * 解析出來以後的資訊都放到 bd 的屬性中
       */
 
      // 解析 <meta />
      parseMetaElements(ele, bd);
      // 解析 <lookup-method />
      parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      // 解析 <replaced-method />
      parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    // 解析 <constructor-arg />
      parseConstructorArgElements(ele, bd);
      // 解析 <property />
      parsePropertyElements(ele, bd);
      // 解析 <qualifier />
      parseQualifierElements(ele, bd);
 
      bd.setResource(this.readerContext.getResource());
      bd.setSource(extractSource(ele));
 
      return bd;
   }
   catch (ClassNotFoundException ex) {
      error("Bean class [" + className + "] not found", ele, ex);
   }
   catch (NoClassDefFoundError err) {
      error("Class that bean class [" + className + "] depends on not found", ele, err);
   }
   catch (Throwable ex) {
      error("Unexpected failure during bean definition parsing", ele, ex);
   }
   finally {
      this.parseState.pop();
   }
 
   return null;
}
複製程式碼

到這裡,我們已經完成了根據 <bean /> 配置建立了一個 BeanDefinitionHolder 例項。注意,是一個。

我們回到解析 <bean /> 的入口方法:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   // 將 <bean /> 節點轉換為 BeanDefinitionHolder,就是上面說的一堆
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      // 如果有自定義屬性的話,進行相應的解析,先忽略
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // 我們把這步叫做 註冊Bean 吧
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // 註冊完成後,傳送事件,本文不展開說這個
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}
複製程式碼

大家再仔細看一下這塊吧,我們後面就不回來說這個了。這裡已經根據一個 <bean /> 標籤產生了一個 BeanDefinitionHolder 的例項,這個例項裡面也就是一個 BeanDefinition 的例項和它的 beanName、aliases 這三個資訊,注意,我們的關注點始終在 BeanDefinition 上:

    public class BeanDefinitionHolder implements BeanMetadataElement {
     
      private final BeanDefinition beanDefinition;
     
      private final String beanName;
     
      private final String[] aliases;
    ...
複製程式碼

然後我們準備註冊這個 BeanDefinition,最後,把這個註冊事件傳送出去。

下面,我們開始說註冊 Bean 吧。

註冊 Bean

// BeanDefinitionReaderUtils 143

public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {
 
   String beanName = definitionHolder.getBeanName();
   // 註冊這個 Bean
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
 
   // 如果還有別名的話,也要根據別名統統註冊一遍,不然根據別名就找不到 Bean 了,這我們就不開心了
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         // alias -> beanName 儲存它們的別名資訊,這個很簡單,用一個 map 儲存一下就可以了,
         // 獲取的時候,會先將 alias 轉換為 beanName,然後再查詢
         registry.registerAlias(beanName, alias);
      }
   }
}
複製程式碼

別名註冊的放一邊,畢竟它很簡單,我們看看怎麼註冊 Bean。

// DefaultListableBeanFactory 793

@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 容器例項化完成後

說到這裡,我們回到 refresh() 方法,我重新貼了一遍程式碼,看看我們說到哪了。是的,我們才說完 obtainFreshBeanFactory() 方法。

考慮到篇幅,這裡開始大幅縮減掉沒必要詳細介紹的部分,大家直接看下面的程式碼中的註釋就好了。

@Override
public void refresh() throws BeansException, IllegalStateException {
   // 來個鎖,不然 refresh() 還沒結束,你又來個啟動或銷燬容器的操作,那不就亂套了嘛
   synchronized (this.startupShutdownMonitor) {
 
      // 準備工作,記錄下容器的啟動時間、標記“已啟動”狀態、處理配置檔案中的佔位符
      prepareRefresh();
 
      // 這步比較關鍵,這步完成後,配置檔案就會解析成一個個 Bean 定義,註冊到 BeanFactory 中,
      // 當然,這裡說的 Bean 還沒有初始化,只是配置資訊都提取出來了,
      // 註冊也只是將這些資訊都儲存到了註冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 
      // 設定 BeanFactory 的類載入器,新增幾個 BeanPostProcessor,手動註冊幾個特殊的 bean
      // 這塊待會會展開說
      prepareBeanFactory(beanFactory);
 
      try {
         // 【這裡需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實現了此介面,
         // 那麼在容器初始化以後,Spring 會負責呼叫裡面的 postProcessBeanFactory 方法。】
 
         // 這裡是提供給子類的擴充套件點,到這裡的時候,所有的 Bean 都載入、註冊完成了,但是都還沒有初始化
         // 具體的子類可以在這步的時候新增一些特殊的 BeanFactoryPostProcessor 的實現類或做點什麼事
         postProcessBeanFactory(beanFactory);
         // 呼叫 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);
 
         // 註冊 BeanPostProcessor 的實現類,注意看和 BeanFactoryPostProcessor 的區別
         // 此介面兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 兩個方法分別在 Bean 初始化之前和初始化之後得到執行。注意,到這裡 Bean 還沒初始化
         registerBeanPostProcessors(beanFactory);
 
         // 初始化當前 ApplicationContext 的 MessageSource,國際化這裡就不展開說了,不然沒完沒了了
         initMessageSource();
 
         // 初始化當前 ApplicationContext 的事件廣播器,這裡也不展開了
         initApplicationEventMulticaster();
 
         // 從方法名就可以知道,典型的模板方法(鉤子方法),
         // 具體的子類可以在這裡初始化一些特殊的 Bean(在初始化 singleton beans 之前)
         onRefresh();
 
         // 註冊事件監聽器,監聽器需要實現 ApplicationListener 介面。這也不是我們的重點,過
         registerListeners();
 
         // 重點,重點,重點
         // 初始化所有的 singleton beans
         //(lazy-init 的除外)
         finishBeanFactoryInitialization(beanFactory);
 
         // 最後,廣播事件,ApplicationContext 初始化完成
         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.
         // 銷燬已經初始化的 singleton 的 Beans,以免有些 bean 會一直佔用資源
         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();
      }
   }
}
複製程式碼

準備 Bean 容器: prepareBeanFactory

這裡簡單介紹下 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) {
   // 設定 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());
   }
}
複製程式碼

初始化所有的 singleton beans

我們的重點當然是 finishBeanFactoryInitialization(beanFactory); 這個巨頭了,這裡會負責初始化所有的 singleton beans。

注意,後面的描述中,我都會使用初始化預初始化來代表這個階段。主要是 Spring 需要在這個階段完成所有的 singleton beans 的例項化。

我們來總結一下,到目前為止,應該說 BeanFactory 已經建立完成,並且所有的實現了 BeanFactoryPostProcessor 介面的 Bean 都已經初始化並且其中的 postProcessBeanFactory(factory) 方法已經得到執行了。所有實現了 BeanPostProcessor 介面的 Bean 也都完成了初始化。

剩下的就是初始化其他還沒被初始化的 singleton beans 了,我們知道它們是單例的,如果沒有設定懶載入,那麼 Spring 會在接下來初始化所有的 singleton beans。

// AbstractApplicationContext.java 834

// 初始化剩餘的 singleton beans
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // 什麼,看程式碼這裡沒有初始化 Bean 啊!
   // 注意了,初始化的動作包裝在 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));
   }
 
   // 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 的時候動態織入,這裡不展開說
   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();
}
複製程式碼

從上面最後一行往裡看,我們又回到 DefaultListableBeanFactory 這個類了,這個類大家應該都不陌生了吧。

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);
 
   // 觸發所有的非懶載入的 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,請移步附錄區瞭解)
         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();
         }
      }
   }
}
複製程式碼

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

getBean

在繼續前進之前,讀者應該具備 FactoryBean 的知識,如果讀者還不熟悉,請移步附錄部分了解 FactoryBean。

// AbstractBeanFactory 196

@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 的話,返回它建立的那個例項物件
      // (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 方法:

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

複製程式碼

第三個引數 args 陣列代表建立例項需要的引數,不就是給構造方法用的引數,或者是工廠 Bean 的引數嘛,不過要注意,在我們的初始化階段,args 是 null。

這回我們要到一個新的類了 AbstractAutowireCapableBeanFactory,看類名,AutowireCapable?類名是不是也說明了點問題了。

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

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

// 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);
   }
 
   // 準備方法覆寫,這裡又涉及到一個概念: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;
}
複製程式碼

建立 Bean

往裡看 doCreateBean 這個方法:

/**
 * 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,這裡例項化 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。

注意了,接下來的這三個方法要認真說那也是極其複雜的,很多地方我就點到為止了,感興趣的讀者可以自己往裡看,最好就是碰到不懂的,自己寫程式碼去除錯它。

建立 Bean 例項

我們先看看 createBeanInstance 方法。需要說明的是,這個方法如果每個分支都分析下去,必然也是極其複雜冗長的,我們挑重點說。此方法的目的就是例項化我們指定的類。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
   // 確保已經載入了此 class
   Class<?> beanClass = resolveBeanClass(mbd, beanName);
 
   // 校驗一下這個類的訪問許可權
   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)  {
      // 採用工廠方法例項化,不熟悉這個概念的讀者請看附錄,注意,不是 FactoryBean
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }
 
   // 如果不是第一次建立,比如第二次建立 prototype bean。
   // 這種情況下,我們可以從第一次建立知道,採用無參建構函式,還是建構函式依賴注入 來完成例項化
   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) {
         // 建構函式依賴注入
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         // 無參建構函式
         return instantiateBean(beanName, mbd);
      }
   }
 
   // 判斷是否採用有參建構函式
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
      // 建構函式依賴注入
      return autowireConstructor(beanName, mbd, ctors, args);
   }
 
   // 呼叫無參建構函式
   return instantiateBean(beanName, mbd);
}
複製程式碼

挑個簡單的無參建構函式構造例項來看看:

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 {
         // 例項化
         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);
   }
}
複製程式碼

我們可以看到,關鍵的地方在於:

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
複製程式碼

這裡會進行實際的例項化過程,我們進去看看:

// SimpleInstantiationStrategy 59

@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
 
   // 如果不存在方法覆寫,那就使用 java 反射進行例項化,否則使用 CGLIB,
   // 方法覆寫 請參見附錄"方法注入"中對 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);
            }
         }
      }
      // 利用構造方法進行例項化
      return BeanUtils.instantiateClass(constructorToUse);
   }
   else {
      // 存在方法覆寫,利用 CGLIB 來完成例項化,需要依賴於 CGLIB 生成子類,這裡就不展開了
      return instantiateWithMethodInjection(bd, beanName, owner);
   }
}
複製程式碼

到這裡,我們就算例項化完成了。我們開始說怎麼進行屬性注入。

bean 屬性注入

// AbstractAutowireCapableBeanFactory 1203

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
   // bean 例項的所有屬性都在這裡了
   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;
      }
   }
 
   // 到這步的時候,bean 例項化完成(通過工廠方法或構造方法),但是還沒開始屬性設值,
   // InstantiationAwareBeanPostProcessor 的實現類可以在這裡對 bean 進行狀態修改,
   // 我也沒找到有實際的使用,所以我們暫且忽略這塊吧
   boolean continueWithPropertyPopulation = true;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 如果返回 false,代表不需要進行後續的屬性設值,也不需要再經過其他的 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。記錄依賴關係
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }
 
      // 通過型別裝配。複雜一些
      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;
               // 這裡有個非常有用的 BeanPostProcessor 進到這裡: AutowiredAnnotationBeanPostProcessor
               // 對採用 @Autowired、@Value 註解的依賴進行設值,這裡的內容也是非常豐富的,不過本文不會展開說了,感興趣的讀者請自行研究
               pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvs == null) {
                  return;
               }
            }
         }
      }
      if (needsDepCheck) {
         checkDependencies(beanName, mbd, filteredPds, pvs);
      }
   }
   // 設定 bean 例項的屬性值
   applyPropertyValues(beanName, mbd, bw, pvs);
}
複製程式碼

initializeBean

屬性注入完成後,這一步其實就是處理各種回撥了。

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 實現了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 介面,回撥
      invokeAwareMethods(beanName, bean);
   }
 
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // BeanPostProcessor 的 postProcessBeforeInitialization 回撥
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
 
   try {
      // 處理 bean 中定義的 init-method,
      // 或者如果 bean 實現了 InitializingBean 介面,呼叫 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 回撥
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}
複製程式碼

大家發現沒有,BeanPostProcessor 的兩個回撥都發生在這邊,只不過中間處理了 init-method,是不是和讀者原來的認知有點不一樣了?

Dubbo啟動和Spring的關係

首先我們來看一下官方demo中給出的Dubbo啟動程式碼:

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"});
        context.start();
        System.in.read(); // press any key to exit
    }
複製程式碼

再看一下配置檔案:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- provider's application name, used for tracing dependency relationship -->
    <dubbo:application name="demo-provider"/>

    <!-- use multicast registry center to export service -->
    <dubbo:registry address="zookeeper://47.107.231.174:2181"/>

    <!-- use dubbo protocol to export service on port 20880 -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!-- service implementation, as same as regular local bean -->
    <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>

    <!-- declare the service interface to be exported -->
    <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/>

</beans>
複製程式碼

可以看到Dubbo啟動的程式碼很簡單,只有三行,通過構建ClassPathXmlApplicationContext來啟動Dubbo。那麼Dubbo是如何在ClassPathXmlApplicationContext構建過程中實現自己的相關邏輯的呢?

在Dubbo的官方文件中是這樣寫的:

基於 dubbo.jar 內的 META-INF/spring.handlers 配置,Spring 在遇到 dubbo 名稱空間時,會回撥 DubboNamespaceHandler

所有 dubbo 的標籤,都統一用 DubboBeanDefinitionParser 進行解析,基於一對一屬性對映,將 XML 標籤解析為 Bean 物件。

這裡提到的spring.handlers配置如下:

http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
複製程式碼

這裡的兩個配置對應了Dubbo從阿里開源到捐贈apache的過程。

我們來看一下Spring中是如何解析Dubbo的配置檔案的:

這是在啟動Dubbo過程中解析檔案的呼叫鏈路

從Dubbo啟動看Dubbo和Spring的關係

可以看到開始啟動之後

執行ClassPathXmlApplicationContext的構造方法,在構造方法中呼叫refresh構造新的ApplicationContext物件,在這裡會載入BeanDefiniton。也就是說會載入我們在Dubbo的配置檔案中的相關配置。

在執行解析對應的Element物件時,會進入BeanDefinitionParserDelegate.class的parseCustomElement方法:

 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        String namespaceUri = this.getNamespaceURI(ele);//首先獲得對應的namespaceUri,這裡對應的namaspaceUri是http://dubbo.apche.org/schema/dubbo
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);//根據namespaceUri獲取對應的Handler 
        if (handler == null) {
            this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        } else {
            return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));//handler執行相應的解析邏輯,最後跳轉到DubboBeanDefinitionParser執行parse方法。
        }
    }
複製程式碼

DefaultNamespaceHandlerResolver.class類:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.beans.factory.xml;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.FatalBeanException;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;

public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {
    public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";//預設的handler配置檔案地址
    protected final Log logger;
    private final ClassLoader classLoader;
    private final String handlerMappingsLocation;
    private volatile Map<String, Object> handlerMappings;//namespaceUri和解析器例項的對映關係

    public DefaultNamespaceHandlerResolver() {
        this((ClassLoader)null, "META-INF/spring.handlers");
    }

    public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
        this(classLoader, "META-INF/spring.handlers");
    }

    public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) {
        this.logger = LogFactory.getLog(this.getClass());
        Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
        this.classLoader = classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader();
        this.handlerMappingsLocation = handlerMappingsLocation;
    }

    public NamespaceHandler resolve(String namespaceUri) {
        Map<String, Object> handlerMappings = this.getHandlerMappings();
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        } else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler)handlerOrClassName;
        } else {
            String className = (String)handlerOrClassName;

            try {
                Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                    throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                } else {
                    NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);//建立對應Handler的例項
                    namespaceHandler.init();//建立之後呼叫init方法
                    handlerMappings.put(namespaceUri, namespaceHandler);//新增到對應map中
                    return namespaceHandler;
                }
            } catch (ClassNotFoundException var7) {
                throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
            } catch (LinkageError var8) {
                throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
            }
        }
    }
	//當需要獲得對應的namespaceUri和handler的對映關係時,使用雙重檢查鎖來構造handlerMapping。
    private Map<String, Object> getHandlerMappings() {
        if (this.handlerMappings == null) {
            synchronized(this) {
                if (this.handlerMappings == null) {
                    try {
                        Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                        if (this.logger.isDebugEnabled()) {
                            this.logger.debug("Loaded NamespaceHandler mappings: " + mappings);
                        }

                        Map<String, Object> handlerMappings = new ConcurrentHashMap(mappings.size());
                        CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                        this.handlerMappings = handlerMappings;
                    } catch (IOException var5) {
                        throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
                    }
                }
            }
        }

        return this.handlerMappings;
    }

    public String toString() {
        return "NamespaceHandlerResolver using mappings " + this.getHandlerMappings();
    }
}

複製程式碼

從上面的類中我們瞭解到handler和namespaceUri的對應關係預設是從META-INF/spring.handlers檔案中讀取,這就是為什麼我們只需要在META-INF/spring.handlers配置對應的解析器,spring就能自動的使用相應的解析去解析對應的名稱空間下的Element物件。

從上面可以看到建立了對應的Handler例項之後,會呼叫該handler的init方法。

DubboNamespaceHandler.java的init方法如下:

 @Override
    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }
複製程式碼

在init方法中,對dubbo中不同的實體註冊了不同的解析器,並指定不同的名稱解析成不同的實體物件。如果後續還需要什麼新的實體新增,只需要在這個地方新增對應的解析器就可以。

return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)):這裡會執行DubboBeanDefinitionParser中的parser方法:

private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
        //建立RootBeanDefinition
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        //解析配置物件的id。若不存在,則進行生成
        String id = element.getAttribute("id");
        if ((id == null || id.length() == 0) && required) {
            String generatedBeanName = element.getAttribute("name");
            if (generatedBeanName == null || generatedBeanName.length() == 0) {
                if (ProtocolConfig.class.equals(beanClass)) {
                    generatedBeanName = "dubbo";
                } else {
                    generatedBeanName = element.getAttribute("interface");
                }
            }
            if (generatedBeanName == null || generatedBeanName.length() == 0) {
                generatedBeanName = beanClass.getName();
            }
            id = generatedBeanName;
            //若id已存在,通過自增序列,解決重複
            int counter = 2;
            while (parserContext.getRegistry().containsBeanDefinition(id)) {
                id = generatedBeanName + (counter++);
            }
        }
        if (id != null && id.length() > 0) {
            if (parserContext.getRegistry().containsBeanDefinition(id)) {
                throw new IllegalStateException("Duplicate spring bean id " + id);
            }
            //新增到Spring的登錄檔
            parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
            //設定Bean的'id'屬性值
            beanDefinition.getPropertyValues().addPropertyValue("id", id);
        }
        //處理<dubbo:protocol/>特殊情況
        if (ProtocolConfig.class.equals(beanClass)) {
            for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
                BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
                PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
                if (property != null) {
                    Object value = property.getValue();
                    if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
                        definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
                    }
                }
            }
            //處理<dubbo:service/>的class的屬性
        } else if (ServiceBean.class.equals(beanClass)) {
            String className = element.getAttribute("class");
            if (className != null && className.length() > 0) {
                RootBeanDefinition classDefinition = new RootBeanDefinition();
                classDefinition.setBeanClass(ReflectUtils.forName(className));
                classDefinition.setLazyInit(false);
                parseProperties(element.getChildNodes(), classDefinition);
                beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
            }
            //解析<dubbo:provider/>的內嵌子元素<dubbo:service/>
        } else if (ProviderConfig.class.equals(beanClass)) {
            parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
        //解析<dubbo:consumer/>的內嵌子元素<dubbo:reference>
        } else if (ConsumerConfig.class.equals(beanClass)) {
            parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
        }
        Set<String> props = new HashSet<String>();
        ManagedMap parameters = null;
        //迴圈Bean物件的setting方法,將屬性賦值到Bean物件
        for (Method setter : beanClass.getMethods()) {
            String name = setter.getName();
            //判斷是否是set方法
            if (name.length() > 3 && name.startsWith("set")
                    && Modifier.isPublic(setter.getModifiers())
                    && setter.getParameterTypes().length == 1) {
                Class<?> type = setter.getParameterTypes()[0];
                //新增'props'
                String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");
                props.add(property);
                Method getter = null;
                //getting&&public&&屬性值型別統一
                try {
                    getter = beanClass.getMethod("get" + name.substring(3), new Class<?>[0]);
                } catch (NoSuchMethodException e) {
                    try {
                        getter = beanClass.getMethod("is" + name.substring(3), new Class<?>[0]);
                    } catch (NoSuchMethodException e2) {
                    }
                }
                if (getter == null
                        || !Modifier.isPublic(getter.getModifiers())
                        || !type.equals(getter.getReturnType())) {
                    continue;
                }
                //解析'<dubbo:parameters/>'
                if ("parameters".equals(property)) {
                    parameters = parseParameters(element.getChildNodes(), beanDefinition);
                    //解析<dubbo:method>
                } else if ("methods".equals(property)) {
                    parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);
                    //解析'<dubbo:argument>'
                } else if ("arguments".equals(property)) {
                    parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);
                } else {
                    String value = element.getAttribute(property);
                    if (value != null) {
                        value = value.trim();
                        if (value.length() > 0) {
                            //不想註冊到註冊中心的情況
                            if ("registry".equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) {
                                RegistryConfig registryConfig = new RegistryConfig();
                                registryConfig.setAddress(RegistryConfig.NO_AVAILABLE);
                                beanDefinition.getPropertyValues().addPropertyValue(property, registryConfig);
                            } else if ("registry".equals(property) && value.indexOf(',') != -1) {
                                //多註冊中心的情況
                                parseMultiRef("registries", value, beanDefinition, parserContext);
                            } else if ("provider".equals(property) && value.indexOf(',') != -1) {
                                //多服務提供者的情況
                                parseMultiRef("providers", value, beanDefinition, parserContext);
                            } else if ("protocol".equals(property) && value.indexOf(',') != -1) {
                                //多協議的情況
                                parseMultiRef("protocols", value, beanDefinition, parserContext);
                            } else {
                                Object reference;
                                //處理屬性為基本屬性的情況
                                if (isPrimitive(type)) {
                                    //相容性處理
                                    if ("async".equals(property) && "false".equals(value)
                                            || "timeout".equals(property) && "0".equals(value)
                                            || "delay".equals(property) && "0".equals(value)
                                            || "version".equals(property) && "0.0.0".equals(value)
                                            || "stat".equals(property) && "-1".equals(value)
                                            || "reliable".equals(property) && "false".equals(value)) {
                                        // backward compatibility for the default value in old version's xsd
                                        value = null;
                                    }
                                    reference = value;
                                    //處理在'<dubbo:provider/>'或者<dubbo:service/>上定義了'protocol'屬性的相容性
                                } else if ("protocol".equals(property)
                                        && ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(value)
                                        && (!parserContext.getRegistry().containsBeanDefinition(value)//存在該登錄檔的實現
                                        || !ProtocolConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName()))) {
                                    //目前,<dubbo:provider protocol=""/>推薦獨立成<dubbo:protocol/>
                                    if ("dubbo:provider".equals(element.getTagName())) {
                                        logger.warn("Recommended replace <dubbo:provider protocol=\"" + value + "\" ... /> to <dubbo:protocol name=\"" + value + "\" ... />");
                                    }
                                    // backward compatibility
                                    ProtocolConfig protocol = new ProtocolConfig();
                                    protocol.setName(value);
                                    reference = protocol;
                                    //處理onreturn屬性
                                } else if ("onreturn".equals(property)) {
                                    //按照'.'拆分
                                    int index = value.lastIndexOf(".");
                                    String returnRef = value.substring(0, index);
                                    String returnMethod = value.substring(index + 1);
                                    //建立RuntimeBeanReference,指向回撥物件
                                    reference = new RuntimeBeanReference(returnRef);
                                    //設定'onreturnMethod'到BeanDefinition的屬性值
                                    beanDefinition.getPropertyValues().addPropertyValue("onreturnMethod", returnMethod);
                                    //處理onthrow屬性
                                } else if ("onthrow".equals(property)) {
                                    //按照'.'拆分
                                    int index = value.lastIndexOf(".");
                                    String throwRef = value.substring(0, index);
                                    String throwMethod = value.substring(index + 1);
                                    //建立RuntimeBeanReference指向回撥物件
                                    reference = new RuntimeBeanReference(throwRef);
                                    //設定’onthrowMethod‘到BeanDefinition的屬性值
                                    beanDefinition.getPropertyValues().addPropertyValue("onthrowMethod", throwMethod);
                                } else if ("oninvoke".equals(property)) {
                                    int index = value.lastIndexOf(".");
                                    String invokeRef = value.substring(0, index);
                                    String invokeRefMethod = value.substring(index + 1);
                                    reference = new RuntimeBeanReference(invokeRef);
                                    beanDefinition.getPropertyValues().addPropertyValue("oninvokeMethod", invokeRefMethod);
                                } else {
                                    //指向Service的bean物件,必須是單例
                                    if ("ref".equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) {
                                        BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);
                                        if (!refBean.isSingleton()) {
                                            throw new IllegalStateException("The exported service ref " + value + " must be singleton! Please set the " + value + " bean scope to singleton, eg: <bean id=\"" + value + "\" scope=\"singleton\" ...>");
                                        }
                                    }
                                    //建立RuntimeBeanReference,指向service的Bean物件
                                    reference = new RuntimeBeanReference(value);
                                }
                                //設定BeanDefinition的屬性值
                                beanDefinition.getPropertyValues().addPropertyValue(property, reference);
                            }
                        }
                    }
                }
            }
        }
        //將XML元素,未在上面遍歷到的屬性新增到'parameters'集合中。
        NamedNodeMap attributes = element.getAttributes();
        int len = attributes.getLength();
        for (int i = 0; i < len; i++) {
            Node node = attributes.item(i);
            String name = node.getLocalName();
            if (!props.contains(name)) {
                if (parameters == null) {
                    parameters = new ManagedMap();
                }
                String value = node.getNodeValue();
                parameters.put(name, new TypedStringValue(value, String.class));
            }
        }
        if (parameters != null) {
            beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
        }
        return beanDefinition;
    }
複製程式碼

這裡Dubbo的配置檔案解析就告一段落。

最後就是如何實現在Dubbo啟動的時候講服務註冊到註冊中心上去,這裡就需要用到前面解析的物件。在前面我們提到DubboBeanDefinitionParser會將service解析為ServiceBean物件。

我們先看看ServiceBean類的實現:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.dubbo.config.spring;

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ModuleConfig;
import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.spring.extension.SpringExtensionFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.AbstractApplicationContext;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * ServiceFactoryBean
 *
 * @export
 */
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {

    private static final long serialVersionUID = 213195494150089726L;

    private final transient Service service;

    private transient ApplicationContext applicationContext;

    private transient String beanName;

    private transient boolean supportedApplicationListener;

    public ServiceBean() {
        super();
        this.service = null;
    }

    public ServiceBean(Service service) {
        super(service);
        this.service = service;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        SpringExtensionFactory.addApplicationContext(applicationContext);
        try {
            Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class); // backward compatibility to spring 2.0.1
            method.invoke(applicationContext, this);
            supportedApplicationListener = true;
        } catch (Throwable t) {
            if (applicationContext instanceof AbstractApplicationContext) {
                try {
                    Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class); // backward compatibility to spring 2.0.1
                    if (!method.isAccessible()) {
                        method.setAccessible(true);
                    }
                    method.invoke(applicationContext, this);
                    supportedApplicationListener = true;
                } catch (Throwable t2) {
                }
            }
        }
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    /**
     * Gets associated {@link Service}
     *
     * @return associated {@link Service}
     */
    public Service getService() {
        return service;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (isDelay() && !isExported() && !isUnexported()) {
            if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + getInterface());
            }
            export();
        }
    }

    private boolean isDelay() {
        Integer delay = getDelay();
        ProviderConfig provider = getProvider();
        if (delay == null && provider != null) {
            delay = provider.getDelay();
        }
        return supportedApplicationListener && (delay == null || delay == -1);
    }

    @Override
    @SuppressWarnings({"unchecked", "deprecation"})
    public void afterPropertiesSet() throws Exception {
        if (getProvider() == null) {
            Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
            if (providerConfigMap != null && providerConfigMap.size() > 0) {
                Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
                if ((protocolConfigMap == null || protocolConfigMap.size() == 0)
                        && providerConfigMap.size() > 1) { // backward compatibility
                    List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() != null && config.isDefault()) {
                            providerConfigs.add(config);
                        }
                    }
                    if (!providerConfigs.isEmpty()) {
                        setProviders(providerConfigs);
                    }
                } else {
                    ProviderConfig providerConfig = null;
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() == null || config.isDefault()) {
                            if (providerConfig != null) {
                                throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
                            }
                            providerConfig = config;
                        }
                    }
                    if (providerConfig != null) {
                        setProvider(providerConfig);
                    }
                }
            }
        }
        if (getApplication() == null
                && (getProvider() == null || getProvider().getApplication() == null)) {
            Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
            if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
                ApplicationConfig applicationConfig = null;
                for (ApplicationConfig config : applicationConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        if (applicationConfig != null) {
                            throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
                        }
                        applicationConfig = config;
                    }
                }
                if (applicationConfig != null) {
                    setApplication(applicationConfig);
                }
            }
        }
        if (getModule() == null
                && (getProvider() == null || getProvider().getModule() == null)) {
            Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
            if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
                ModuleConfig moduleConfig = null;
                for (ModuleConfig config : moduleConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        if (moduleConfig != null) {
                            throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
                        }
                        moduleConfig = config;
                    }
                }
                if (moduleConfig != null) {
                    setModule(moduleConfig);
                }
            }
        }
        if ((getRegistries() == null || getRegistries().isEmpty())
                && (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().isEmpty())
                && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) {
            Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
            if (registryConfigMap != null && registryConfigMap.size() > 0) {
                List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
                for (RegistryConfig config : registryConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        registryConfigs.add(config);
                    }
                }
                if (!registryConfigs.isEmpty()) {
                    super.setRegistries(registryConfigs);
                }
            }
        }
        if (getMonitor() == null
                && (getProvider() == null || getProvider().getMonitor() == null)
                && (getApplication() == null || getApplication().getMonitor() == null)) {
            Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
                MonitorConfig monitorConfig = null;
                for (MonitorConfig config : monitorConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        if (monitorConfig != null) {
                            throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
                        }
                        monitorConfig = config;
                    }
                }
                if (monitorConfig != null) {
                    setMonitor(monitorConfig);
                }
            }
        }
        if ((getProtocols() == null || getProtocols().isEmpty())
                && (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().isEmpty())) {
            Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
            if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
                List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
                for (ProtocolConfig config : protocolConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        protocolConfigs.add(config);
                    }
                }
                if (!protocolConfigs.isEmpty()) {
                    super.setProtocols(protocolConfigs);
                }
            }
        }
        if (getPath() == null || getPath().length() == 0) {
            if (beanName != null && beanName.length() > 0
                    && getInterface() != null && getInterface().length() > 0
                    && beanName.startsWith(getInterface())) {
                setPath(beanName);
            }
        }
        if (!isDelay()) {
            export();
        }
    }

    @Override
    public void destroy() throws Exception {
        // This will only be called for singleton scope bean, and expected to be called by spring shutdown hook when BeanFactory/ApplicationContext destroys.
        // We will guarantee dubbo related resources being released with dubbo shutdown hook.
        //unexport();
    }

    // merged from dubbox
    @Override
    protected Class getServiceClass(T ref) {
        if (AopUtils.isAopProxy(ref)) {
            return AopUtils.getTargetClass(ref);
        }
        return super.getServiceClass(ref);
    }
}

複製程式碼

可以看到ServiceBean繼承了ServiceConfig類,實現了InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware。

1547365712339

InitializingBean

只包括afterPropertiesSet()方法,繼承該介面的類,在初始化bean的時候會執行該方法。在構造方法之後呼叫。

DisposableBean

DisposableBean也是一個介面,提供了一個唯一的方法destory()。在Bean生命週期結束前呼叫destory()方法做一些收尾工作.

init-method destory-method

@PostConstruct 和 @PreDestroy

Constructor  >> @Autowired >> @PostConstruct

ApplicationContextAware

Spring容器會檢測容器中的所有Bean,如果發現某個Bean實現了ApplicationContextAware介面,Spring容器會在建立該Bean之後,自動呼叫該Bean的setApplicationContextAware()方法,呼叫該方法時,會將容器本身作為引數傳給該方法

ApplicationListener

當Spring容器初始化完成之後,會釋出一個ContextRefreshedEvent事件,實現ApplicationListener介面的類,會呼叫*onApplicationEvent(E event)*方法。

BeanNameAware

public void setBeanName(String beanName) {

this.beanName = beanName;

}

獲得自己的名字

BeanFactoryAware

讓Bean獲取配置他們的BeanFactory的引用。

在Spring註冊完成之後會呼叫finishRefresh方法,在該方法中會呼叫實現了ApplicationListenner類的onApplicationEvent方法。

public void onApplicationEvent(ContextRefreshedEvent event) {
        if (isDelay() && !isExported() && !isUnexported()) {
            if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + getInterface());
            }
            export();
        }
    }
複製程式碼

ServiceBean的OnApplicationEvent方法如上,可以看到在該方法中呼叫了export實現了服務的註冊。

再看一看ReferenceBean的實現:

public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {

    private static final long serialVersionUID = 213195494150089726L;

    private transient ApplicationContext applicationContext;

    public ReferenceBean() {
        super();
    }

    public ReferenceBean(Reference reference) {
        super(reference);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        SpringExtensionFactory.addApplicationContext(applicationContext);
    }

    @Override
    public Object getObject() {
        return get();
    }

    @Override
    public Class<?> getObjectType() {
        return getInterfaceClass();
    }

    @Override
    @Parameter(excluded = true)
    public boolean isSingleton() {
        return true;
    }

    @Override
    @SuppressWarnings({"unchecked"})
    public void afterPropertiesSet() throws Exception {
        if (getConsumer() == null) {
            Map<String, ConsumerConfig> consumerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class, false, false);
            if (consumerConfigMap != null && consumerConfigMap.size() > 0) {
                ConsumerConfig consumerConfig = null;
                for (ConsumerConfig config : consumerConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        if (consumerConfig != null) {
                            throw new IllegalStateException("Duplicate consumer configs: " + consumerConfig + " and " + config);
                        }
                        consumerConfig = config;
                    }
                }
                if (consumerConfig != null) {
                    setConsumer(consumerConfig);
                }
            }
        }
        if (getApplication() == null
                && (getConsumer() == null || getConsumer().getApplication() == null)) {
            Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
            if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
                ApplicationConfig applicationConfig = null;
                for (ApplicationConfig config : applicationConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        if (applicationConfig != null) {
                            throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
                        }
                        applicationConfig = config;
                    }
                }
                if (applicationConfig != null) {
                    setApplication(applicationConfig);
                }
            }
        }
        if (getModule() == null
                && (getConsumer() == null || getConsumer().getModule() == null)) {
            Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
            if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
                ModuleConfig moduleConfig = null;
                for (ModuleConfig config : moduleConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        if (moduleConfig != null) {
                            throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
                        }
                        moduleConfig = config;
                    }
                }
                if (moduleConfig != null) {
                    setModule(moduleConfig);
                }
            }
        }
        if ((getRegistries() == null || getRegistries().isEmpty())
                && (getConsumer() == null || getConsumer().getRegistries() == null || getConsumer().getRegistries().isEmpty())
                && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) {
            Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
            if (registryConfigMap != null && registryConfigMap.size() > 0) {
                List<RegistryConfig> registryConfigs = new ArrayList<>();
                for (RegistryConfig config : registryConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        registryConfigs.add(config);
                    }
                }
                if (!registryConfigs.isEmpty()) {
                    super.setRegistries(registryConfigs);
                }
            }
        }
        if (getMonitor() == null
                && (getConsumer() == null || getConsumer().getMonitor() == null)
                && (getApplication() == null || getApplication().getMonitor() == null)) {
            Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
                MonitorConfig monitorConfig = null;
                for (MonitorConfig config : monitorConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault()) {
                        if (monitorConfig != null) {
                            throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
                        }
                        monitorConfig = config;
                    }
                }
                if (monitorConfig != null) {
                    setMonitor(monitorConfig);
                }
            }
        }
        Boolean b = isInit();
        if (b == null && getConsumer() != null) {
            b = getConsumer().isInit();
        }
        if (b != null && b) {
            getObject();
        }
    }

    @Override
    public void destroy() {
        // do nothing
    }
}

複製程式碼

在ReferenceBean中是通過FactoryBean來實現消費服務去註冊中心拉取相應的服務,建立對應的proxy的。

相關文章