spring步步前行(IOC)-整理篇

從之前的ioc部分的源碼分析等,我們對spring-ioc部分的相關已經有了一部分認識和了解,但是還是有很多人對裏面一些部分的理解還是很模糊,好比既然有了beanFactory那factoryBean是幹什麼的,在ioc中有很多相關的aware這種後綴的類的命名,感覺應該有聲明上的相似,但是卻可能在之前的文章都一筆帶過了…

​ 鑑於諸如此類的,我想通過demo的方式,從表現形式上來區分所謂的beanFactory和FactoryBean,以及aware這類的意義

BeanFactory與FactoryBean

對於FactoryBean而言,想要體現factoryBean的強大的話,需結合AOP才能體現出來其強大,這裏我們先初步分析,留待之後與AOP結合分析,爲什麼要與AOP結合分析,我們先看看官方描述

出自FactoryBean官方註釋說明:

		A bean that implements this interface cannot be used as a normal bean. A FactoryBean is defined in a bean style, but the object exposed for bean references ({@link #getObject()}) is always the object that it creates.

		This interface is heavily used within the framework itself, for example for the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for custom components as well; however, this is only common for infrastructure code.

雖然FactoryBean定義爲一個bean的形式,但是會通過getObject方法將一些對象暴露出來,我們可以通過ProxyFactoryBean的getObject中先了解下可知任何實現了beanFactory的bean都可通過getObject獲取這個類型的bean

官方在AOP的ProxyFactoryBean或JndiObjectFactoryBean中有這兩個類可作爲示例,接口是在框架內大量使用,也能被使用在自定義的組建,然後這個僅在基礎結構代碼中常見

上一篇咱們簡單的提及了factoryBean, 我們藉助beanFactory通過"&"+beanName的方法查找class,現在我們就看下spring對這塊的官方說明

在這裏插入圖片描述

即在beanFactory中有這一個說明,就是其通過&這個符號來獲取factoryBean,到此factoryBean我們就瞭解到,其FactoryBean的getObject()返回的對象,而不是FactoryBean本身, 如果要獲取FactoryBean對象,可以在id前面加一個&符號來獲取

廢話不多說直接上實例:

首先我們既然要看factorybean,那我們就實現一個,既然官方爲我們提供了ProxyFactoryBean和JndiObjectFactoryBean中兩個類作爲示例,那我們就從示例中類比寫出一個簡單的factoryBean來印證

  • 實現factorybean接口

    public class ProxyMyFactoryBean implements FactoryBean {
    
        public Object getObject() throws Exception {
            return null;
        }
    
        public Class<?> getObjectType() {
            return null;
        }
    
        public boolean isSingleton() {
            return false;
        }
    }
    
  • factoryBean中只有三個方法,我們一邊結合官方註釋和官方示例的ProxyFactoryBean來"豐滿"各個方法

    • getObject方法

      在這裏插入圖片描述

      官方的描述是這樣的"返回一個在factory中被管理的類的實例"

    • isSingleton()方法

      在這裏插入圖片描述

      即在factory中被管理的類是否是單例的

      在ProxyFactoryBean中其實現的getObject()的方法用了以上兩個方法

      在這裏插入圖片描述我們不關心其中間的實現,我們就關注其返回結果,可發現,如果是單例的話,就通過創建單例的方式創建一個實例返回,否則的話,就直接創建一個對象返回

    • getObjectType方法

      在這裏插入圖片描述

      可瞭解其是返回factoryBean創建的實例的類型,可能有些人跟我一樣理解不了要這玩意兒幹啥,我們再看看其具體描述"這個方法允許在不實例化對象的情況下檢查特定類型的bean,例如在autowiring時",感覺有點用還是不太清楚,看看示例輔助下

      在這裏插入圖片描述

      從這裏我們也關注其返回的結果,

      • 單例實例時,就返回該實例的class對象,否則的話獲取代理接口,
      • 如果是一個的多就返回該代理接口的class對象
      • 如果是多個的話就創建一個組合接口的class對象
      • 如果targetName不爲null且beanFactory不爲null就從beanFactory中找到tagetName的class類型返回
      • 如果均不符合,那就返回targetSource的class

      簡單理解就是返回我們getObject創建實例的關聯類的class

  • "豐滿"我們的factoryBean

    • 準備工作,由於其是返回示例所以我們需要創建類來輔助我們

      public class TargetA {
          public void print() {
              System.out.println("-----print--AAA----succeed---");
          }
      }
      public class TargetB {
          public void print() {
              System.out.println("-----print--BBB----succeed---");
          }
      }
      
    • "豐滿”工作

      public class ProxyMyFactoryBean implements FactoryBean {
      
          private String targetName;
      
          public void setTargetName(String targetName) {
              this.targetName = targetName;
          }
      
          public Object getObject() throws Exception {
              if("aaa".equals(targetName)) {
                  return new TargetA();
              }
              return new TargetB();
          }
      
          public Class<?> getObjectType() {
              if("aaa".equals(targetName)) {
                  return TargetA.class;
              }
              return TargetB.class;
          }
      
          public boolean isSingleton() {
              return false;
          }
      }
      
    • 創建bean的xml配置factorybean信息

      <bean id="proxyMyFactoryBean" class="org.tutor.spring.ioc.bean.ProxyMyFactoryBean">
              <property name="targetName" value="aaa"/>
      </bean>
      
    • 運行結果

      在這裏插入圖片描述

      從其運行結果我們都能獲取到targetA的實例用以操控

  • 總結

    beanFactory就不在此處詳細介紹,不過我們做一下從上面運行的方式,我們都能看到無論beanFactory還是FactoryBean我們都能獲取我們想要的實例對象

    • beanFactory相當於bean的容器,可以理解成工廠,內可以幫我們創建bean,對bean進行管理

    • factoryBean雖然也可以創建bean,其更多的是對class上進行代理處理,從我們的測試方法,我們很容易就可以想到,明顯代理的痕跡

      這裏我引用一張圖加以理解

      在這裏插入圖片描述

      就是我們通過設置目標的class屬性從factoryBean中獲取目標class的代理對象

      可能有人會疑問爲什麼會有這樣的設計,其實spring在aop中已經回答我們,不過我們也可以從代理模式的優點能理解其意義也是可以

      • 在符合開閉原則的情況下對目標對象進行功能擴展

      那麼我們就可以大膽的猜想,其就是爲了讓我們在持有目標對象時,豐富對象功能,也可以不在關注具象實現,有需求方關注(具體我們在AOP處,對ProxyFactoryBean的應用處可瞭解)

BeanNameAware與BeanFactoryAware

在這裏插入圖片描述

BeanNameAware是對於需要獲取在beanFactory的beanName的時候就實現

在這裏插入圖片描述

BeanFactoryAware是由對應的BeanFactory實現的,即可獲取該bean所在的beanFactory名稱,可以獲取配置他們的BeanFactory的引用

總結

由於BeanNameAware和BeanFactoryAware均都是spring內實現,故其實對我們應用及其有限,但它們對spring而言,卻不一樣,我們可以從spring代碼書寫來理解

  • BeanNameAware

    在這裏插入圖片描述

    類似這樣,本身springLifeBean沒有什麼意義,只是我們做的一個標記,便於理解

  • BeanFactoryAware

    這個方法可能是在根據某個配置文件創建了一個新工廠之後,Spring才調用這個方法,並把BeanFactory注入到Bean中。
    讓bean獲取配置自己的工廠之後,當然可以在Bean中使用這個工廠的getBean()方法,但是,實際上非常不推薦這樣做,因爲結果是進一步加大Bean與Spring的耦合,而且,能通過DI注入進來的儘量通過DI來注入。
    當然,除了查找bean,BeanFactory可以提供大量其他的功能,例如銷燬singleton模式的Bean。
    factory.preInstantiateSingletons();方法。preInstantiateSingletons()方法立即實例化所有的Bean實例,有必要對這個方法和Spring加載bean的機制做個簡單說明。
    方法本身的目的是讓Spring立即處理工廠中所有Bean的定義,並且將這些Bean全部實例化。因爲Spring默認實例化Bean的情況下,採用的是lazy機制,換言之,如果不通過getBean()方法(BeanFactory或者ApplicationContext的方法)獲取Bean的話,那麼爲了節省內存將不實例話Bean,只有在Bean被調用的時候才實例化它們

    引用自網上對BeanFactoryAware的描述

Springbean的初始化順序

​ 對於IOC我們也分析有一段時間了,既然IOC是對bean的操作,那麼我們還沒有正面關注過,接下來,通過bean的初始化過程,繼續鞏固一路走來的IOC分析

​ 在我們分析SpringFactory的refresh時候,其依次順序是aware 然後InitializingBean,最後進入的是postProcessor,那我們通過實現這些接口看看其的順序是否跟我們的refresh分析是否相左

  • 準備工作

    創建一個類,實現’BeanFactoryAware,BeanNameAware,BeanFactoryPostProcessor,BeanPostProcessor,InitializingBean’這些接口

    public class TestLifeCycleBean implements BeanFactoryAware,BeanNameAware,BeanFactoryPostProcessor,BeanPostProcessor,InitializingBean {
    
        private String name;
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public TestLifeCycleBean() {
            System.out.println("into... 構造函數");
        }
    
        /**
         * init-method
         */
        public void initMethod(){
            System.out.println("into... init-method");
        }
    
        public void say(){
            System.out.println("into... say hello I am "+name);
        }
    
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out.println("into... setBeanFactory and beanFactory is "+beanFactory);
        }
    
        public void setBeanName(String s) {
            System.out.println("into...  setBeanName and name is "+s);
        }
    
        public void afterPropertiesSet() throws Exception {
            System.out.println("into... InitializingBean接口的afterPropertiesSet and name is "+ name);
        }
    
    
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
            System.out.println("into... BeanFactoryPostProcessor接口的postProcessBeanFactory and this beanFactory is "+configurableListableBeanFactory);
        }
    
        public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
            System.out.println("into... BeanPostProcessor接口的postProcessBeforeInitialization: "+o.getClass());
            return o;
        }
    
        public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
            System.out.println("into... BeanPostProcessor接口的postProcessAfterInitialization: "+o.getClass());
            return o;
        }
    }
    

    在這裏可能我們打印的結果可能是這樣的

    在這裏插入圖片描述

    很明顯BeanPostProcessor的相關方法並沒有產生作用,這是我們之前的大戰BeanPostProcessor有說明,我們只用實例化一個bean即可

    在這裏插入圖片描述

    總結其springbean的初始化順序

    • 1.先執行構造函數
    • 2.之行BeanNameAware方法
    • 3.執行BeanFactoryAware方法
    • 4.之行InitializingBean方法
    • 5.執行指定的init-method方法
    • 6.執行BeanFactoryPostProcessor方法
    • 7.最後纔有BeanPostProcessor方法

回顧之前的refresh

有沒有豁然開朗的感覺?!就先整理這些吧,持續整理更新…

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