向Spring大佬低頭——大量源碼流出解析

優秀的源碼中有着多年沉積下來的精華,這些精華是很是值得咱們學習的。放棄閱讀源碼,你將失去一個和大師學習的機會。html


用Spring框架作了幾年的開發,只停留在會用的階段上,然而Spring的設計思想和原理確實一個巨大的寶庫。大部分人僅僅知道怎麼去配,或着加上什麼屬性就能達到什麼效果,這些東西均可以經過查文檔,查google來解決。關鍵是在怎麼理解它,把它的思想變爲本身的東西。這幾天沒有學習(裝逼),感受內心甚是空虛,索×××了下一直很好奇的Spring大佬,畢竟寫代碼每天都在用。java

前方高能,非戰鬥人員迅速投入戰鬥:web

  1. Spring IOC容器面試

  2. ApplicationContext與BeanFactory探究.spring

  3. bean的加載數據庫

  4. FactoryBean緩存

  5. Spring AOP實現原理及實戰安全

文章篇幅有限,只對Spring幾個重要的知識點進行簡單闡述,有興趣的能夠看看《Spring源碼深度解析》,該書下載地址:https://pan.baidu.com/s/1jGxdGTg,本文也是基於該書總結出來的。微信

1.Spring IOC容器

不少人一提IOC,便張口就來:控制反轉。究竟哪些方面被反轉了呢?答案是依賴對象的得到被反轉了。不少時候,咱們經過多個對象之間的協做來完成一個功能,若是獲取所依賴對象靠自身來實現,這將致使代碼的耦合度高和難以測試。固然,控制反轉還有一個好聽的名字:依賴注入。session

Spring IOC經過引入xml配置,由IOC容器來管理對象的生命週期,依賴關係等。

從圖中能夠看出,咱們之前獲取兩個有依賴關係的對象,要用set方法,而用容器以後,它們之間的關係就由容器來管理。那麼,Spring容器的加載過程是什麼樣的呢?

BeanDefinition是一個接口,用於屬性承載,好比<bean>元素標籤擁有class、scope、lazy-init等配置。bean的定義方式有千千萬萬種,不管是何種標籤,不管是何種資源定義,不管是何種容器,只要按照Spring的規範編寫xml配置文件,最終的bean定義內部表示都將轉換爲內部的惟一結構:BeanDefinition。當BeanDefinition註冊完畢之後,Spring的BeanFactory就能夠隨時根據須要進行實例化了。

2.ApplicationContext與BeanFactory探究

實例化的工做會在容器啓動後過AbstractApplicationContext中reflash方法自動進行。咱們經常使用的ApplicationContext實現類ClassPathXmlApplicationContext繼承了AbstractApplicationContext類,繼承關係以下圖.

                                

AbstractApplicationContext裏的reflash方法是Spring初始IOC容器一個很是重要的方法,無論你是ApplicationContext哪一個實現類,最終都會進入這個方法。

@Override  
   public void refresh() throws BeansException, IllegalStateException {  
       synchronized (this.startupShutdownMonitor) {  
           // 設置和校驗系統變量和環境變量的值
           prepareRefresh();  

           //主要是建立beanFactory,同時加載配置文件.xml中的beanDefinition  
           //經過String[] configLocations = getConfigLocations()獲取資源路徑,而後加載beanDefinition  
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
 

           //給beanFactory註冊一些標準組建,如ClassLoader,StandardEnvironment,BeanProcess  
           prepareBeanFactory(beanFactory);  
 
           try {  
 
               //提供給子類實現一些postProcess的註冊,如AbstractRefreshableWebApplicationContext註冊一些Servlet相關的  
                //postProcess,真對web進行生命週期管理的Scope,經過registerResolvableDependency()方法註冊指定ServletRequest,HttpSession,WebRequest對象的工廠方法  
                postProcessBeanFactory(beanFactory);  
  
               //調用全部BeanFactoryProcessor的postProcessBeanFactory()方法  
               invokeBeanFactoryPostProcessors(beanFactory);  
 
               //註冊BeanPostProcessor,BeanPostProcessor做用是用於攔截Bean的建立  
               registerBeanPostProcessors(beanFactory);  
   
               //初始化消息Bean  
               initMessageSource();  
 
               //初始化上下文的事件多播組建,ApplicationEvent觸發時由multicaster通知給ApplicationListener  
                initApplicationEventMulticaster();  

               //ApplicationContext初始化一些特殊的bean  
               onRefresh();  
  
               //註冊事件監聽器,事件監聽Bean統一註冊到multicaster裏頭,ApplicationEvent事件觸發後會由multicaster廣播  
                registerListeners();  
 
               //非延遲加載的單例Bean實例化  
               finishBeanFactoryInitialization(beanFactory);  
 
               finishRefresh();  
           }  
 
           catch (BeansException ex) {  
               logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);  

               destroyBeans();  

               cancelRefresh(ex);  
 
               throw ex;  
           }  
       }  
   }

        

代碼邏輯清晰的值得mark一下。這個方法的做用是建立加載Spring容器配置(包括.xml配置,property文件和數據庫模式等)。

BeanFactory體系結構是典型的工廠方法模式,即什麼樣的工廠生產什麼樣的產品。要知道工廠是如何產生對象的,咱們須要看具體的IOC容器實現,具體的實現有:如 DefaultListableBeanFactory 、 XmlBeanFactory 、 ApplicationContext 等。那麼,究竟BeanFactory裏究竟是什麼樣的呢?

package org.springframework.beans.factory;

public interface BeanFactory {

   /**
    * 用來引用一個實例,或把它和工廠產生的Bean區分開,就是說,若是一個FactoryBean的名字爲a,那麼,&a會獲得那個Factory
     */

   String FACTORY_BEAN_PREFIX = "&";

   /*
    * 四個不一樣形式的getBean方法,獲取實例
    */

   Object getBean(String name) throws BeansException;

   <T> getBean(String name, Class<T> requiredType) throws BeansException;

   <T> getBean(Class<T> requiredType) throws BeansException;

   Object getBean(String name, Object... args) throws BeansException;

   boolean containsBean(String name)// 是否存在

   boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 是否爲單實例

   boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 是否爲原型(多實例)

   boolean isTypeMatch(String name, Class<?> targetType)
           throws NoSuchBeanDefinitionException
;// 名稱、類型是否匹配

   Class<?> getType(String name) throws NoSuchBeanDefinitionException; // 獲取類型

   String[] getAliases(String name);// 根據實例的名字獲取實例的別名

}


咱們能夠看出BeanFactory裏只對IOC容器的基本行爲做了定義,根本不關心你的bean是如何定義怎樣加載的,它規定了全部的容器至少須要實現的標準。說到實現,BeanFactory有幾個比較重要的實現類須要知道,ref:【Spring4揭祕 BeanFactory】基本容器-BeanFactory:https://blog.csdn.net/u011179993/article/details/51636742。那麼BeanFactory的基本實現類XmlBeanFactory與咱們經常使用的ApplicationContext有什麼區別呢?答案是bean的加載。

3.bean的加載

咱們先看一道面試常常會問到的問題:Spring的bean在何時實例化? ——第一:若是你使用BeanFactory,如XmlBeanFactory做爲Spring Bean的工廠類,則全部的bean都是在第一次使用該bean的時候實例化 。第二:若是你使用ApplicationContext做爲Spring Bean的工廠類,則又分爲如下幾種狀況: 

  1. 若是bean的scope是singleton的,而且lazy-init爲false(默認是false,因此能夠不用設置),則ApplicationContext啓動的時候就實例化該bean,而且將實例化的bean放在一個線程安全的 ConcurrentHashMap 結構的緩存中,下次再使用該Bean的時候,直接從這個緩存中取 。

  2. 若是bean的scope是singleton的,而且lazy-init爲true,則該bean的實例化是在第一次使用該bean的時候進行實例化 。

  3. 若是bean的scope是prototype的,則該bean的實例化是在第一次使用該Bean的時候進行實例化 。

ClassPathXmlApplicationContext有幾個重載的構造函數最終都會調用父類AbstractApplicationContext的reflash方法,reflash方法在前文有介紹,做用是建立加載Spring容器配置。AbstractApplicationContext也有getBean方法:

AbstractApplicationContext下的代碼:
public Object getBean(String name) throws BeansException {
       //Bean的獲取外部容器交給了內部容器
       return getBeanFactory().getBean(name);
}

內部容器由DefaultListableBeanFactory承當,但真實的getBean方法實現是由其父類AbstractBeanFactory實現的,AbstractBeanFactory類一樣實現了BeanFactory接口的方法,它有四個重載的getBean方法,無論哪個都會去調用doGetBean方法:

那麼doGetBean裏幹了什麼事情呢?

protected <T> T doGetBean(
     final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException { 
//bean name處理,去除FactoryBean前綴等  
    final String beanName = transformedBeanName(name);  
    Object bean = null;  
 
//先從singleton緩存中查看是否已經實例化過該Bean,根據是否有緩存分爲兩個分支分別處理  
   Object sharedInstance = getSingleton(beanName);  
   if (sharedInstance != null && args == null) {  
// 分支一,若緩存中獲取到了而且該BeanDefinition信息代表該bean是singleton的,直接將獲取到的緩存Bean  
//(有多是半成品)交給getObjectForBeanInstance處理  
/*.........省略logger部分代碼............*/  
//調用getObjectForBeanInstance處理  
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  
   }else {  
// 分之二:沒有緩存,則須要從頭實例化該bean  
           // We're assumably within a circular reference.  
     if (isPrototypeCurrentlyInCreation(beanName)) {   
          throw new BeanCurrentlyInCreationException(beanName);}  
 
// 檢查BeanDefinition是否在當前工廠或父工廠  
           BeanFactory parentBeanFactory = getParentBeanFactory();  
           if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {  
               // Not found -> check parent.  
               String nameToLookup = originalBeanName(name);  
               if (args != null) {  
// 父工廠getBean  
                   return parentBeanFactory.getBean(nameToLookup, args);  
               }  
               else {  
                   // No args -> delegate to standard getBean method.  
                   return parentBeanFactory.getBean(nameToLookup, requiredType);  
               }  
           }  
//將bean加入「正在建立」的集合,完成後會remove,對應afterSingletonCreation/afterPrototypeCreation方法  
            if (!typeCheckOnly) {  
               markBeanAsCreated(beanName);  
           }  
 
           final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
           checkMergedBeanDefinition(mbd, beanName, args);  
 
// 解決依賴關係,將依賴的bean提早實例化  
           String[] dependsOn = mbd.getDependsOn();  
           if (dependsOn != null) {  
               for (int i = 0; i < dependsOn.length; i++) {  
                   String dependsOnBean = dependsOn[i];  
                   getBean(dependsOnBean);  
                   registerDependentBean(dependsOnBean, beanName);  
               }  
           }  
 
// 這裏又須要根據bean的類型分爲三種狀況:singleton、prototype、request/session  
           if (mbd.isSingleton()) {  
                          //經過自定義ObjectFactory實例化Bean,此結果多是半成品(是FactoryBean等)  
                sharedInstance = getSingleton(beanName, new ObjectFactory() {  
                   public Object getObject() throws BeansException {  
                       try {  
                         //真正實例化裝配的邏輯在createBean方法中  
                           return createBean(beanName, mbd, args);  
                       }  
                       catch (BeansException ex) {   
                           destroySingleton(beanName);  
                           throw ex;  
                       }  
                   }  
               });  
                       //上一步半成品的Bean交給getObjectForBeanInstance方法處理  
               bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);  
           }  
 
           else if (mbd.isPrototype()) {  
               Object prototypeInstance = null;  
               try {  
                   beforePrototypeCreation(beanName);  
                    //真正實例化裝配的邏輯在createBean方法中  
                   prototypeInstance = createBean(beanName, mbd, args);  
               }  
               finally {  
                   afterPrototypeCreation(beanName);  
               }  
                   //上一步半成品的Bean交給getObjectForBeanInstance方法處理  
              bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);  
           }  
 
           else {  
                           //request、session 的bean  
               String scopeName = mbd.getScope();  
               final Scope scope = (Scope) this.scopes.get(scopeName);  
               if (scope == null) {  
       throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");  
                }  
               try {  
                   Object scopedInstance = scope.get(beanName, new ObjectFactory() {  
                       public Object getObject() throws BeansException {  
                           beforePrototypeCreation(beanName);  
                           try {  
                        //真正實例化裝配的邏輯在createBean方法中  
                               return createBean(beanName, mbd, args);  
                           }  
                           finally {  
                               afterPrototypeCreation(beanName);  
                           }  
                       }  
                   });  
                      //上一步半成品的Bean交給getObjectForBeanInstance方法處理  
               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);  
               }  
           }  
       }  
  
       if (requiredType != null && bean != null &&  
                             !requiredType.isAssignableFrom(bean.getClass())) {  
           throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());  
       }  
       return bean;  
   }

    

bean的加載經歷了一個複雜的過程,上面代碼主要作了如下幾件事(此段摘抄自《Spring源碼深度解析》):

    1.轉換對應的beanName。若是name=「&aa」的,會去除&符號。或者<bean>標籤帶有alias(別名的意思),則取alias所表示最終的beanName。

    2.嘗試從緩存中加載單例bean。若是加載不成功,會再次嘗試從singletonFactories中加載。

    3.bean的實例化。假如咱們須要對工廠bean進行處理,那麼這裏獲得的實際上是工廠bean 的初始狀態。真正幹活的則是getObjectForBeanInstance定義factory-method方法返回的bean。

    4.原型模式的依賴檢查。若是A類有B的屬性,B中有A的屬性,則會產生循環依賴。參考:spring如何解決循環依賴問題http://www.cnblogs.com/bhlsheji/p/5208076.html

    5.將存儲的Xml配置文件的GernericBeanDefinition轉換爲RootBeanDefinition。前文提到的用於承載屬性的BeanDefinition有三個實現,GernericBeanDefinition,RootBeanDefinition和ChildBeanDefinition,若是父類bean不爲空的話,這裏會把全部的屬性一併合併父類屬性,由於後續全部的Bean都是針對RootBeanDefinition的。

    6.尋找依賴。在初始化一個bean的時候,會首先初始化這個bean所對應的依賴。

    7.根據不一樣的scope建立bean。scope屬性默認是singleton,還有prototype、request等。

    8.類型轉換。若是bean是個String,而requiredType傳入了Integer,而後返回bean,加載結束。

其中,最重要的步驟是(7),spring的經常使用特性都在那裏實現.

4.FactoryBean

首先要分辨BeanFactory 與 FactoryBean的區別, 兩個名字很像,因此容易搞混。這裏作一個簡單的比喻你就明白了:

    1.FactoryBean:工廠類接口,用戶能夠經過實現該接口定製實例化 bean的邏輯。咱們把bean比做是人,那麼FactoryBean則是女媧,首先它自己有人的特徵,但它可以生產人。

    2.BeanFactory :BeanFactory定義了 IOC 容器的最基本形式。若是bean還比做是人,那麼它能夠理解成三界,三界裏有各類功能的人,它是一個容器,能夠管理不少的人。

FactoryBean裏幹了什麼事情?

public interface FactoryBean<T{

   //返回由FactoryBean建立的Bean實例,若是isSingleton返回true,則該實例會放到spring容器中單例緩存池中.
  getObject() throws Exception;

  //返回FactoryBean建立的bean類型.
 Class<?> getObjectType();

   //返回由FactoryBean建立的bean實例的做用域是singleton仍是prototype
 boolean isSingleton();

}


它的做用不在這裏作闡述,ref:Spring的FactoryBean使用http://www.cnblogs.com/quanyongan/p/4133724.html

寫到這裏,總結一下閱讀Spring源碼的心得:

    1.學習Spring思想和編碼規範。Spring的不少函數代碼量大,邏輯複雜,而Spring的編碼風格就是將複雜的邏輯分解,分紅N個小函數的嵌套,每一層都是對下一層的總結和概要。在工做中最佩服的一個大神說過:學習Spring源碼思想爲我所用,哪怕是一天學習一個變量名,他在工做中設計不少小組件的時候都是基於Spring思想和規範。他說,不要迷茫學什麼技術,其實天天只要進步一點點就好,突破的是本身,而不是某個領域。用10年其實才敢說入門一門技術。

    2.跟了Spring代碼的函數,你會或多或少發現一些規律:一個真正幹活的函數實際上是以do開頭的,如doGetBean,而給咱們錯覺的函數,如getBean和createBean等等方法,其實只是從全局角度作一些統籌工做。

    3.放棄閱讀源碼是一個不明智的選擇,由於你失去了跟大師學習的機會。當你硬着頭皮讀完一個框架的源碼,則其餘框架都是相通的。

    4.下一篇文章:Spring AOP是什麼?你都拿它作什麼?   由於篇幅有限,AOP又是一個重要且內容比較多的部分,因此打算單獨拿出來搞事情。


我有一個微信公衆號,常常會分享一些Java技術相關的乾貨;若是你喜歡個人分享,能夠用微信搜索「Java團長」或者「javatuanzhang」關注。

相關文章
相關標籤/搜索