spring Bean

1. Bean的裝載與管理

Spring框架中,一旦把一個Bean歸入到Spring IoC容器之中,這個Bean的生命週期就會交由容器進行管理,通常擔當管理者角色的是BeanFactory或ApplicationContex。web

將Bean元數據收集裝載

BeanDefinition:用於管理各類對象以及它們之間相互依賴關係的核心數據結構。spring

Resource:用來封裝IO操做的類。編程

 收集過程:經過refresh方法啓動,包括BeanDefinition和Resource的定位、載入、註冊三個基本過程:緩存


 -- 定位:即尋找數據的過程,指對BeanDefinition的資源定位,由ResourceLoader經過統一的Resource接口完成。
 -- 載入:把用戶定義好的Bean表示成IOC容器的內部數據結構,即BeanDefinition(POJO對象在IOC容器中的抽象)
 -- 註冊:將BeanDefinition注入到HashMap中,IOC容器就是經過這個HahMap來管理數據。

 

BeanFactory接口

Spring 的容器最基本的接口就是:BeanFactory。BeanFactory 負責配置、建立及管理bean。數據結構

調用者只需使用getBean 方法便可得到指定bean的引用,無須關心bean 的實例化過程。即bean 實例的建立過程徹底透明。app

經過BeanFactory獲取Bean框架

在UserService中注入tool字段,經過BeanFactory來實現獲取函數

UserService實現BeanFactoryAware接口的setBeanFactory方法,Spring會調用setBeanFactory方法將BeanFactory注入到UserService的factory字段(須要注意UserService須要被實例化,能夠經過xml來配置bean,也能夠經過@component類的註解來將Bean裝載到容器實例化),而後就能夠經過setBeanFactory獲取Bean。post

 

ApplicationContext接口

獲取Bean推薦使用ApplicationContext,由於其是BeanFactory 的子接口,提供了更多面嚮應用的功能。ui

經過ApplicationContext獲取Bean:

和BeanFactory同樣,SpringConfigTool類也須要實例化,ApplicationContext才能被注入到context字段上,能夠經過XML或者@component類型的註解,將Bean注入。

BeanFactory與ApplicationContext區別:

1. BeanFacotry延遲加載,即只有在使用到某個Bean時(調用getBean()),纔對該Bean
  進行加載實例化,若是Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次
  使用調用getBean方法纔會拋出異常;而ApplicationContext則在初始化自身是檢驗,
  這樣有利於檢查所依賴屬性是否注入;因此一般狀況下咱們選擇使用
  ApplicationContext。ApplicationContext則會在上下文啓動後預載入全部的單
  實例Bean。經過預載入單實例bean ,確保當你須要的時候,你就不用等待,由於它們
  已經建立好了。
2. 一旦單例被實例化就會被放入緩存Bean池,下次獲取直接返回,而多例則每一次都建立
  一個新對象返回,並將控制權移交給用戶,由用戶管理Bean的生命週期,使用完後須要
  顯示設置爲null,幫助回收。BeanFactory只能管理單例Bean,而
  ApplicationContext也能夠管理多例Bean。
3. BeanFactory和ApplicationContext都支持BeanPostProcessor、
  BeanFactoryPostProcessor的使用,但二者之間的區別是:BeanFactory須要手動
  註冊,而ApplicationContext則是自動註冊。(Applicationcontext比
  beanFactory 加入了一些更好使用的功能。並且 BeanFactory的許多功能須要經過
  編程實現而 Applicationcontext 能夠經過配置實現。好比後處理 bean ,
  Applicationcontext 直接配置在配置文件便可而 BeanFactory這要在代碼中顯示
  的寫出來才能夠被容器識別)。
4. BeanFactory主要是面對與 Spring 框架的基礎設施,面對 spring 本身。而
  Applicationcontext主要面對與 Spring 使用的開發者。基本都會使用
  Applicationcontext並不是 BeanFactory。

 

2. Bean 的生命週期

 

BeanFactory實例化Bean屬性相關實例化順序

一、調用Bean的默認構造方法,或者在指定的構造方法,生成bean實例(暫稱爲instance1);

三、若是Bean的配置文件中注入了Bean屬性值,則在instance1基礎上進行屬性注入造成instance2,這種注入是覆蓋性的。

二、若是Bean實現了InitializingBean接口,則調用afterPropertiesSet()方法,來改變或操做instance2,獲得instance3;

四、若是Bean的配置文件中指定了init-ethod="init"屬性,則會調用指定的初始化方法,則在instance3的基礎上調用初始化方法init(),將對象最終初始化爲instance4;初始化的名字任意。

 

Bean的具體加載與初始化

  1. 實例化一個Bean(由BeanFactory讀取Bean定義文件,並生成各個實例)--也就是咱們常說的new;

  2. 按照Spring上下文對實例化的Bean的屬性值進行設置--也就是IOC注入;

  3. 若是這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String)方法,此處傳遞的就是Spring配置文件中Bean的id值

  4. 若是這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory(setBeanFactory(BeanFactory)傳遞的是Spring工廠自身(能夠用這個方式來獲取其它Bean,只需在Spring配置文件中配置一個普通的Bean就能夠);

  5. 若是這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文(一樣這個方式也能夠實現步驟4的內容,但比4更好,由於ApplicationContext是BeanFactory的子接口,有更多的實現方法);

  6. 若是這個Bean關聯了BeanPostProcessor接口,將會調用postProcessBeforeInitialization(Object obj, String s)方法

初始化以前構造注入依賴以後執行

  1. 若是Bean類實現了org.springframework.beans.factory.InitializingBean接口,則執行其afterPropertiesSet()方法。

通常是用來在實例構造完成後,實例的應該注入的依賴屬性已經完成注入,須要對不須要注入的實例屬性進行自定義初始化配置;固然也可指定一個init-method方法完成初始化,二者的做用同樣,都是完成用戶自定義初始化。對於單例,若是bean實現了InitializingBean接口則afterPropertiesSet方法只會被調用一次;不然每次建立bean時afterPropertiesSet方法都會被從新調用。

  1. 若是Bean在Spring配置文件中配置了init-method屬性會自動調用其配置的初始化方法。

或者使用@PostConstruct後構造註解來將任意方法名稱的方法標明爲一個init-method方法

  1. 若是這個Bean關聯了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法;

注:以上工做完成之後就能夠應用這個Bean了,若是這個Bean是一個Singleton的,則將這準備就緒的Bean放入Spring緩存池中,已被下次使用,因此通常狀況下咱們調用同一個id的Bean會是在內容地址相同的實例,固然在Spring配置文件中也能夠配置非Singleton,此時不會將Bean放入緩存池中,而是直接將控制權交給Bean的使用者。

  1. 當Bean再也不須要時,會通過清理階段,若是Bean實現了DisposableBean這個接口,會調用那個其實現的destroy()方法;

  2. 最後,若是這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷燬方法。

可使用@PreDestroy前銷燬註解,標明一個方法爲destroy-method

說明: 若是Bean是由BeanFactory管理,則沒有第五步,一樣若是由ApplicationContext管理,則沒有第四步。

摘自Spring BeanFactoy官方文檔:

 

Bean factory implementations should support the standard bean lifecycle interfaces as far as possible. The full set of initialization methods and their standard order is:

-- BeanNameAware's setBeanName

-- BeanClassLoaderAware's setBeanClassLoader

-- BeanFactoryAware's setBeanFactory

-- EnvironmentAware's setEnvironment

-- EmbeddedValueResolverAware's setEmbeddedValueResolver

-- ResourceLoaderAware's setResourceLoader (only applicable when running in an application context)

-- ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context)

-- MessageSourceAware's setMessageSource (only applicable when running in an application context)

-- ApplicationContextAware's setApplicationContext (only applicable when running in an application context)

-- ServletContextAware's setServletContext (only applicable when running in a web application context)

-- postProcessBeforeInitialization methods of BeanPostProcessors

-- InitializingBean's afterPropertiesSet

-- a custom init-method definition

-- postProcessAfterInitialization methods of BeanPostProcessors

 

On shutdown of a bean factory, the following lifecycle methods apply:

-- postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors

-- DisposableBean's destroy

-- a custom destroy-method definition

 

3. 裝配註解

  • @Autowired,該註解的做用是:能夠對成員變量、方法和構造函數進行註解,來完成自動裝配的工做,通俗來講就是會根據類型從容器中自動查到到一個Bean給bookDAO字段。@Autowired是根據類型進行自動裝配的,若是須要按名稱進行裝配,則須要配合@Qualifier。另外可使用其它註解,
  • @ Resource :等同於@Qualifier
  • @Inject:等同於@ Autowired。

 

 @Resource

默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean纔會按照類型來裝配注入;

@Autowired

默認是按照類型裝配注入的,若是想按照名稱來轉配注入,則須要結合@Qualifier一塊兒使用;

@Resource

註解是又J2EE提供,而@Autowired是由spring提供,故減小系統對spring的依賴建議使用@Resource的方式;若是Maven項目是1.5的JRE則需換成更高版本的。

@Resource和@Autowired均可以書寫註解在字段或者該字段的setter方法之上

@Autowired

能夠對成員變量、方法以及構造函數進行註釋,而 @Qualifier 的註解對象是成員變量、方法入參、構造函數入參。

@Qualifier("XXX")

中的 XX是 Bean 的名稱,因此 @Autowired 和 @Qualifier 結合使用時,自動注入的策略就從 byType 轉變成 byName 了。

@Autowired 註釋進行自動注入時

Spring 容器中匹配的候選 Bean 數目必須有且僅有一個,經過屬性required能夠設置非必要。

參考:https://www.jianshu.com/p/f4ef69419bb2?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

  https://www.jianshu.com/p/9062236edeea

相關文章
相關標籤/搜索