Spring框架基礎(chǔ)

Spring框架的核心功能:

  1. Spring 容器作為超級大工廠,負(fù)責(zé)創(chuàng)建、管理所有的Java對象,這些Java對象被稱為 Bean。
  2. Spring 容器管理容器中 Bean 之間的依賴關(guān)系,Spring 使用一種被稱為“依賴注入”的方式來管理 Bean 之間的依賴關(guān)系。

當(dāng)某個Java對象(調(diào)用者)需要調(diào)用另一個Java對象(被調(diào)用者)的方法時,傳統(tǒng)方式:

  • 原始做法:調(diào)用者主動創(chuàng)建被依賴的對象,然后再調(diào)用被依賴對象的方法
  • 簡單工廠模式:調(diào)用者先找到被依賴的工廠,然后主動通過工廠去獲取被依賴對象,最后再調(diào)用被依賴對象的方法。

使用依賴注入,不僅可以為 Bean 注入普通的屬性值,還可以注入其它 Bean 的引用。通過這種依賴注入,Java EE 應(yīng)用中的各個組件不需要以硬編碼的方式耦合在一起,甚至無需使用工廠模式。調(diào)用者獲取被依賴對象的方式由原來的主動獲取,變成被動接受,即控制反轉(zhuǎn)。控制反轉(zhuǎn)和依賴注入其實是同一種行為的兩種表達(dá),只是描述的角度不同而已。

依賴注入的兩種方式:

設(shè)值注入

IoC 容器使用成員變量的setter方法來注入被依賴對象。
<property name="axe" ref="steelAxe"></property>

構(gòu)造注入

IoC容器使用構(gòu)造器來注入被以來對象:直接調(diào)用有參數(shù)的構(gòu)造器,當(dāng)Bean實例創(chuàng)建完成之后,已經(jīng)完成了依賴關(guān)系的注入
<constructor-arg ref ="steelAxe"></constructor-arg>

兩種方式對比

這兩種注入方式?jīng)]有絕對的好壞,只是適應(yīng)的場景有所不同

設(shè)值注入的優(yōu)點:
  • 與傳統(tǒng)的 JavaBean的寫法相比,程序開發(fā)人員更容易理解、接受。通過setter方法設(shè)定依賴關(guān)系顯得更加直觀自然。
  • 對于復(fù)雜的依賴關(guān)系,采用構(gòu)造注入會導(dǎo)致構(gòu)造器過于臃腫,難以閱讀。
  • 尤其在某些成員變量可選的情況下,多參數(shù)的構(gòu)造器更加笨重。
構(gòu)造注入的優(yōu)點:
  • 構(gòu)造注入可以在構(gòu)造器中決定依賴關(guān)系的注入順序,優(yōu)先依賴的優(yōu)先注入。
  • 對于依賴關(guān)系無需變化的Bean,構(gòu)造注入更有用處。因為沒有setter方法,所有的依賴關(guān)系全部在構(gòu)造器內(nèi)設(shè)定。因此無需擔(dān)心后續(xù)代碼對依賴關(guān)系產(chǎn)生破壞。
  • 依賴關(guān)系只能在構(gòu)造器中設(shè)定,只有組件的創(chuàng)建者才能改變組件的依賴關(guān)系。對于組件的調(diào)用者而言,組件內(nèi)部的依賴關(guān)系完全透明,更符合高內(nèi)聚的原則。

建議采用以設(shè)值注入為主,構(gòu)造注入為輔的注入策略。對于依賴關(guān)系無變化的注入,盡量采用構(gòu)造注入;而其它依賴關(guān)系的注入,則考慮采用設(shè)值注入。

Spring容器

Spring容器最基本的接口是BeanFactory,它負(fù)責(zé)配置、創(chuàng)建、管理Bean,它有一個子接口:ApplicationContext,因此也被成為Spring上下文。Spring容器還負(fù)責(zé)管理Bean與Bean之間的依賴關(guān)系。
BeanFactory接口包含以下幾個基本方法:

boolean containsBean(String name);
<T> T getBean(Class<T> requiredType);
Object getBean(String name);
<T> T getBean(String name, Class RequiredType);
Class<?> getType(String name);

ApplicationContext是BeanFactory的子接口,對于大部分的Java EE 應(yīng)用而言,使用它作為Spring容器更為方便,其常用實現(xiàn)類:FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和AnnotationConfigApplicationContext。如果在Web應(yīng)用中使用Spring容器,則通常有XmlWebApplicationContext、AnnotationCongifWebApplicationContext兩個實現(xiàn)類。
ApplicationContext允許以聲明式方式操作容器,無需手動創(chuàng)建。除了提供BeanFactory所支持的全部功能之外,還有如下額外的功能:

  • 默認(rèn)初始化所有的singleton Bean(系統(tǒng)前期創(chuàng)建ApplicationContext將會有較大的系統(tǒng)開銷,一旦初始化完成,程序后面獲取singleton Bean實例將會擁有較好的性能),也可以通過配置取消預(yù)初始化(lazy-init="true")。
  • 繼承MessageSource接口,因此提供國家化支持。
  • 資源訪問。
  • 事件機(jī)制。
  • 同時加載多個配置文件。
  • 以聲明式方式啟動并創(chuàng)建Spring容器。

創(chuàng)建Bean的三種方式

  1. 使用構(gòu)造器創(chuàng)建Bean實例
  2. 使用靜態(tài)工廠方法創(chuàng)建Bean實例
    <Bean.../>元素需要制定兩個屬性:
  • class:該屬性值設(shè)置為靜態(tài)工廠類的類名
  • factory-method:該屬性指定靜態(tài)工廠方法來生產(chǎn)Bean實例
    若靜態(tài)工廠方法需要參數(shù),則使用<constructor-arg.../>元素傳入
  1. 使用實例工廠方法創(chuàng)建Bean實例
    <Bean.../>元素需要制定兩個屬性:
  • factory-bean:該屬性值設(shè)置為工廠Bean的id
  • factory-method:該屬性指定實例工廠方法來生產(chǎn)Bean實例

使用這種方法時,必須將實例工廠配置成Bean的還是理;而配置靜態(tài)工廠方法創(chuàng)建Bean時無需配置工廠Bean。

深入理解容器中的Bean

Spring框架絕大部分工作都集中在對容器中Bean的管理上,包括管理容器中Bean的生命周期,使用Bean繼承等。

抽象Bean和子Bean

將多個<bean.../>配種中相同的信息提取出來,集中成配置模板——這個配置模板不是真正的Bean,Spring容器不應(yīng)該創(chuàng)建該配置模板,于是需要為該<bean.../>增加abstract="true",即抽象Bean。抽象Bean不能實例化。
將大部分相同信息配置成抽象Bean之后,將實際的Bean實例配置成該抽象Bean的子Bean即可。子Bean定義可以從父Bean繼承實現(xiàn)類,構(gòu)造參數(shù)、屬性值等配置信息。除此之外,子Bean配置可以增加新的配置信息,并可指定新的配置信息覆蓋父Bean的定義。

Bean繼承與Java繼承的區(qū)別
  1. 子Bean和父Bean可以是不同的類型
  2. Bean的繼承是實例之間的關(guān)系,主要表現(xiàn)為參數(shù)值的延續(xù)
  3. 子Bean不可以作為父Bean使用,不具有多態(tài)性
獲取Bean本身的id

可借助Spring提供的 BeanNameAware接口,實現(xiàn)該接口,并實現(xiàn)該接口提供的setBeanName()方法。這個方法會在容器創(chuàng)建完該Bean之后,由Spring容器自動調(diào)用。

強(qiáng)制初始化Bean

為了顯示指定被依賴Bean在目標(biāo)Bean之前初始化,可以使用depends-on屬性,該屬性可以在初始化主調(diào)Bean之前,強(qiáng)制初始化一個或多個Bean。

容器中Bean的生命周期

Spring可以管理singleton 作用于的Bean的生命周期,可以精確地知道該Bean何時被創(chuàng)建、何時被初始化完成、容器何時準(zhǔn)備銷毀該Bean實例。
對于prototype作用域的Bean,Spring僅僅負(fù)責(zé)創(chuàng)建,創(chuàng)建完成之后,Bean實例完全交給客戶端代碼管理,容器不再跟蹤其生命周期。
兩個時機(jī):

  1. 注入依賴關(guān)系之后
  2. 即將銷毀Bean之前
依賴關(guān)系注入之后的行為

Spring提供兩種方式在Bean全部屬性設(shè)置成功后執(zhí)行特定行為

使用init-method屬性,只是增加一個普通的方法,沒有代碼污染。
實現(xiàn)InitializingBean接口,實現(xiàn)其 void afterPropertiesSet() Throws Exception方法,污染代碼。

若同時使用兩種方式,則先執(zhí)行接口中的方法,再執(zhí)行屬性指定的方法,下同。

Bean銷毀之前的行為

Spring也提供了兩種方式定制Bean實例銷毀之前的特定行為

使用destroy-method屬性
實現(xiàn)DisposableBean接口,實現(xiàn)void destroy() Throws Exception方法

如何讓Spring容器優(yōu)雅地關(guān)閉呢?在JVM里注冊一個關(guān)閉鉤子(shutdown hook)

AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// 相應(yīng)的業(yè)務(wù)代碼
// 為Spring容器注冊關(guān)閉鉤子,程序?qū)谕顺鯦VM之前關(guān)閉Spring容器
// 并保證關(guān)閉Spring之前調(diào)用singleton Dean實例的析構(gòu)回調(diào)方法。
ctx.registerShutdownHook();
協(xié)調(diào)作用于不同步的Bean

當(dāng)singleton作用域的Bean依賴prototype作用域的Bean時,Spring容器會在初始化singleton作用域的Bean之前,先創(chuàng)建prototype作用域的Bean,然后才初始化singleton Bean,并將prototype Bean注入到singleton Bean。在這種情況下,singleton Bean訪問prototype Bean時得到的永遠(yuǎn)是最初的那個prototype Bean,會產(chǎn)生不同步的情況。解決方法:

  • 放棄依賴注入,代碼主動向容器請求Bean實例。
  • 利用方法注入:lookup方法
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,616評論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,276評論 6 342
  • 文章作者:Tyan博客:noahsnail.com 3.4 Dependencies A typical ente...
    SnailTyan閱讀 4,503評論 2 7
  • 中企動力最近聽到很多聲音:現(xiàn)在國內(nèi)經(jīng)濟(jì)不景氣那么企業(yè)靠哪些本事才能抵御寒冬?“互聯(lián)網(wǎng)+”是今年大熱的概念移動互聯(lián)網(wǎng)...
    武松打虎123閱讀 361評論 0 1
  • 心情很復(fù)雜,或許是因為成長,或許是因為自己的不成功。人生路上,總有幾個陪著你走的人,可是能陪你走多遠(yuǎn),走多久,確是...
    施蠡閱讀 89評論 0 0

友情鏈接更多精彩內(nèi)容