Spring學(xué)習(xí)筆記(四、Bean裝配(上))

上一篇:Spring學(xué)習(xí)筆記(三、IoC)

** Bean常用的配置項(xiàng)**

  • Id:在IoC容器中Bean的唯一標(biāo)識(shí)
  • Class:具體要實(shí)例化的類
  • Scope:作用域
  • Constructor arguments:構(gòu)造器參數(shù)
  • properties:屬性
  • Autowiring mode:自動(dòng)裝配模式
  • lazy-initialization mode:懶加載模式
  • initialization/destruction method:初始化/銷毀的方法

Bean的作用域

  • singleton:?jiǎn)卫敢粋€(gè)Bean容器中只存在一份(默認(rèn))
  • prototype:每次請(qǐng)求(每次使用)創(chuàng)建新的實(shí)例,destory方法不生效(因?yàn)橛猛陼?huì)被垃圾回收期回收)
  • request:每次http請(qǐng)求創(chuàng)建一個(gè)實(shí)例且僅在當(dāng)前request內(nèi)有效
  • session: 每次http請(qǐng)求創(chuàng)建一個(gè)實(shí)例且僅在當(dāng)前session內(nèi)有效
  • global session:基于portlet的web中有效(portlet定義了global session),如果是在web中,同session

這里global session有可能還是不懂,特此解釋:舉個(gè)例子,一個(gè)大型的系統(tǒng),有多個(gè)獨(dú)立的模塊組成,他們有一個(gè)統(tǒng)一的登錄入口,登錄進(jìn)入后,用戶可以在整個(gè)系統(tǒng)內(nèi)操作,不需要在登錄其他模塊時(shí),重新登錄。這就是portlet的global session。

下面用例子證明:

  • singleton
    在TestDao增加接口:


    Paste_Image.png

    TestDaoImpl實(shí)現(xiàn):


    Paste_Image.png

    spring-ioc.xml:
    Paste_Image.png

    JUnit測(cè)試:
Paste_Image.png
Paste_Image.png

上圖可見,聲明了singleton作用域,即使獲取多次實(shí)例,也依舊是原來的那一個(gè)。

  • prototype

修改spring-ioc.xml:

Paste_Image.png

Junit測(cè)試結(jié)果變成:

Paste_Image.png

上圖可見,聲明了prototype作用域,獲取多次實(shí)例,每一次的hashcode都不同。

余下三個(gè),由于涉及到web,在此就不做測(cè)驗(yàn)了。相信工作中,會(huì)有很多機(jī)會(huì)去嘗試。

Bean的生命周期

  • 生命周期
    • 定義:在xml中定義<bean></bean>內(nèi)容
    • 初始化:IoC容器啟動(dòng)(context.start();)時(shí)生成bean的實(shí)例
    • 使用:在測(cè)試或者開發(fā)時(shí)從Ioc容器中取出bean的實(shí)例調(diào)用它的方法
    • 銷毀:在IoC容器銷毀(context.destroy();)的時(shí)候,銷毀它創(chuàng)建的所有實(shí)例。

生命周期 —— 初始化

  1. 實(shí)現(xiàn)org.springframework.beans.factory.InitializingBean接口,重寫afterPropertiesSet方法
  2. 配置init-method
    以上兩種方法,可以在Ioc容器初始化實(shí)例時(shí)執(zhí)行一些實(shí)例內(nèi)部的初始化工作。
    下面分別舉例:

Paste_Image.png
Paste_Image.png

為了測(cè)試IoC容器啟動(dòng),我加了一個(gè)空的測(cè)試方法。

Paste_Image.png

執(zhí)行后

Paste_Image.png

第一個(gè)【實(shí)現(xiàn)org.springframework.beans.factory.InitializingBean接口,重寫afterPropertiesSet方法】測(cè)試初始化成功。


Paste_Image.png
Paste_Image.png
Paste_Image.png

第二個(gè)【配置init-method】測(cè)試初始化成功。


**生命周期 —— 銷毀 **

  1. 實(shí)現(xiàn)org.springframework.beans.factory.DisposableBean接口,重寫destroy方法
  2. 配置destroy-method
    這兩個(gè)銷毀方式和初始化測(cè)試方式是一樣的,我就不做測(cè)試了。

還可以配置全局默認(rèn)初始化、銷毀方法,就是為當(dāng)前IoC容器中所有的bean增加初始化和銷毀時(shí)執(zhí)行的方法

Paste_Image.png

既然實(shí)現(xiàn)初始化和銷毀有三種不同的方法,那么哪種優(yōu)先級(jí)最高呢?下面來測(cè)試。

package test4;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * Created by amber on 2017/5/27.
 */
public class TestInitial3 implements InitializingBean,DisposableBean {

    public void initInBean() {
        System.out.println("Bean內(nèi)自定義init——start——" + hashCode());

    }

    public void destroyInBean(){
        System.out.println("Bean內(nèi)自定義destroy——stop——" + hashCode());
    }

    public void defaultInit() {
        System.out.println("IoC全局默認(rèn)defaultInit——start——" + hashCode());
    }


    public void defaultDestroy(){
        System.out.println("IoC全局默認(rèn)defaultDestroy——stop——" + hashCode());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("重寫接口afterPropertiesSet——start——" + hashCode());
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("重寫接口DisposableBean——stop" + hashCode());
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
       default-init-method="defaultInit" default-destroy-method="defaultDestroy">

    <bean id="testInitial3" class="test4.TestInitial3" init-method="initInBean" destroy-method="destroyInBean"></bean>

 </beans>

測(cè)試后結(jié)果:

Paste_Image.png

發(fā)現(xiàn),三種初始化和銷毀方法同時(shí)執(zhí)行時(shí),全局默認(rèn)的是不執(zhí)行的。其次,最先執(zhí)行的是接口。然后是bean內(nèi)自定義的。
也就是三個(gè)優(yōu)先級(jí)為:接口>Bean中配置>全局默認(rèn)
其中全局默認(rèn)即使配置了,類里面不寫也不會(huì)報(bào)錯(cuò),其他兩個(gè),則會(huì)報(bào)錯(cuò)。


Aware

  • Spring中提供了一些以Aware結(jié)尾的接口,實(shí)現(xiàn)了Aware接口的bean在被初始化之后,可以獲取相應(yīng)資源
  • 通過實(shí)現(xiàn)Aware接口,可以對(duì)Spring相應(yīng)資源進(jìn)行操作(一定要慎重)
  • 為對(duì)Spring進(jìn)行簡(jiǎn)單的擴(kuò)展,提供了方便的接口

Aware相關(guān)常用接口

  • ApplicationContextAware:實(shí)現(xiàn)了此接口的bean,可以獲取到當(dāng)前ApplicationContext的信息。這個(gè)類就可以方便獲得ApplicationContext中的所有bean。換句話說,就是這個(gè)類可以直接獲取spring配置文件中,所有有引用到的bean對(duì)象。
  • BeanNameAware:實(shí)現(xiàn)了此接口的bean,可以獲取到自己在IoC中的beanId。

以上接口,都是在bean初始化時(shí)候調(diào)用。

下面測(cè)試接口功能是否如上所述:

package test5;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * Created by amber on 2017/5/27.
 */
public class TestAware implements ApplicationContextAware, BeanNameAware {

    private String beanName;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("setApplicationContext執(zhí)行時(shí)間戳:" + System.currentTimeMillis());
        System.out.println("獲取當(dāng)前bean的hashCode:" + applicationContext.getBean(beanName).hashCode());
    }

    @Override
    public void setBeanName(String name) {
        beanName = name;
        System.out.println("setBeanName執(zhí)行時(shí)間戳:" + System.currentTimeMillis());

    }
}

IoC容器中

<bean id="testAware" class="test5.TestAware"></bean>

單元測(cè)試中

 @Test
    public void testAware(){
        System.out.println("單元測(cè)試獲取bean的hashCode:"+getBean("testAware").hashCode());
    }

結(jié)果如下。
為什么我要加時(shí)間戳呢,主要是為了看哪個(gè)回調(diào)會(huì)先執(zhí)行,經(jīng)過多次測(cè)試發(fā)現(xiàn)BeanNameAware的setBeanName(String name)會(huì)先執(zhí)行。

Paste_Image.png

Bean的自動(dòng)裝配(AutoWiring)
為什么需要自動(dòng)裝配?
其實(shí)目的很簡(jiǎn)單,是偷懶。自動(dòng)裝配可以不用讓我們?cè)贗oC容器的Bean中聲明這些東西啦:

 <property name="testDao" ref="testDao"/>
 <constructor-arg name="testDao" ref="testDao"/>

關(guān)于Spring自動(dòng)裝配可以參考:spring的自動(dòng)裝配

本次講設(shè)置在<beans>根節(jié)點(diǎn)的全局:default-autowire

  • No:(默認(rèn))不自動(dòng)裝配。Bean的引用必須用ref元素定義。對(duì)于較大的部署不建議改變默認(rèn)設(shè)置,因?yàn)槊鞔_指定協(xié)作者能更好控制和維護(hù)系統(tǒng)。 在某種程度上,它記錄了系統(tǒng)的結(jié)構(gòu)。
  • byName:通過屬性名稱自動(dòng)裝配。Spring會(huì)尋找相同名稱的bean并將其與屬性自動(dòng)裝配。譬如,如果bean的定義設(shè)置了根據(jù)名稱自動(dòng)裝配, 并且包含了一個(gè)master 屬性(換句話說,它有setMaster(..)方法),Spring會(huì)尋找名為master的bean的定義,并用它來裝配屬性
  • byType:如果容器中存在一個(gè)與指定屬性類型相同的bean,那么將與該屬性自動(dòng)裝配。如果存在多個(gè)該類型的bean,將會(huì)拋出異常,并指出不能使用byType自動(dòng)裝配這個(gè)bean。如果沒有找到相同類型的,什么也不會(huì)發(fā)生。屬性不會(huì)被設(shè)置。
  • Constructor:和byType類似,不同之處在于它應(yīng)用于構(gòu)造器參數(shù)。如果在容器中沒有找到與構(gòu)造器參數(shù)類型一致的bean,就會(huì)拋出異常。

在測(cè)試之前呢,先把結(jié)構(gòu)拋出來:


4
Paste_Image.png
Paste_Image.png
Paste_Image.png

自動(dòng)裝配之byName:要保證beanId和調(diào)用它的類屬性名稱一致。

Paste_Image.png
Paste_Image.png

自動(dòng)裝配之byType:將IoC容器中AutoWiringDao的id去掉,只留下class。

Paste_Image.png
Paste_Image.png

自動(dòng)裝配之constructor:

Paste_Image.png
Paste_Image.png

Resource

  • 針對(duì)于資源文件的統(tǒng)一接口
  • Resources
    • UrlResource:URL對(duì)應(yīng)的資源,根據(jù)一個(gè)Url地址即可構(gòu)建
    • ClassPathResource:獲取類路徑下的資源文件
    • FieSystemResource:獲取文件系統(tǒng)里面的資源
    • ServletContextResource:ServletContext封裝的資源,用于訪問ServletContext環(huán)境下的資源
    • InputStreamResource:針對(duì)于輸入流封裝的資源
    • ByteArrayResource:針對(duì)于字節(jié)數(shù)封裝的資源

Resource Loader

  • ResourceLoader 接口是用來加載 Resource 對(duì)象的,換句話說,就是當(dāng)一個(gè)對(duì)象需要獲取 Resource 實(shí)例時(shí),可以選擇實(shí)現(xiàn) ResourceLoader 接口。
  • spring 里所有的應(yīng)用上下文都是實(shí)現(xiàn)了 ResourceLoader 接口,因此,所有應(yīng)用上下文都可以通過 getResource() 方法獲取 Resource 實(shí)例。

Resource Loader接口詳情:


Paste_Image.png

可以看到,我們需要傳入一個(gè)location進(jìn)去,然后接口會(huì)返回一個(gè)對(duì)應(yīng)Resource給我們。那么location這個(gè)值,我們都可以傳哪樣的呢?

前綴 樣例 說明
classpath: classpath:com/myapp/config.xml 從類路徑加載
file: file:///data/config.xml 將其作為 URL 對(duì)象,從文件系統(tǒng)加載
http: http://myserver/logo.png 將其作為 URL 對(duì)象 加載
(none) /data/config.xml 取決于底層的 ApplicationContext

下面來測(cè)試:

使用classpath獲取資源

1.首先在resource文件夾下增加一個(gè)config.txt文件。

Paste_Image.png

2.新建一個(gè)TesrResource類,并通過實(shí)現(xiàn)ApplicationContextAware接口獲取到ApplicationContext,然后傳入classpath:位置的地址得到目標(biāo)文件信息。

Paste_Image.png

3.IoC容器注冊(cè)bean


Paste_Image.png

4.測(cè)試

Paste_Image.png

5.結(jié)果

Paste_Image.png

使用file:獲取資源

1.修改TestResource類的resource方法

Paste_Image.png

2.測(cè)試結(jié)果:

Paste_Image.png

使用http:獲取資源

1.修改resource方法

Paste_Image.png

2.測(cè)試結(jié)果


Paste_Image.png

不使用前綴獲取資源

1.修改resource方法

Paste_Image.png

2.測(cè)試結(jié)果

Paste_Image.png

為什么沒有前綴也能獲取到我們想要的文件呢?

  • 當(dāng)你在指定應(yīng)用上下文調(diào)用 getResource() 方法時(shí),而指定的位置路徑又沒有包含特定的前綴,spring 會(huì)根據(jù)當(dāng)前應(yīng)用上下文來決定返回哪一種類型 Resource。
  • 這個(gè)例子,我們ApplicationContext是通過ClassPathXmlApplicationContext獲取到的,所以返回的是ClassPathResource對(duì)象。類似的,如果是通過實(shí)例 FileSystemXmlApplicationContext 實(shí)例調(diào)用的,返回的是一個(gè) FileSystemResource 對(duì)象;如果是通過 WebApplicationContext 實(shí)例的,返回的是一個(gè) ServletContextResource 對(duì)象…… 如上所說,你就可以在指定的應(yīng)用上下中使用 Resource 實(shí)例來加載當(dāng)前應(yīng)用上下文的資源。

下一篇:Spring學(xué)習(xí)筆記(五、Bean裝配(下))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,570評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評(píng)論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,786評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,219評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,438評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,971評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,796評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,995評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,230評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評(píng)論 1 286
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,697評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,785評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,898評(píng)論 6 342
  • 什么是Spring Spring是一個(gè)開源的Java EE開發(fā)框架。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,509評(píng)論 1 133
  • Spring容器高層視圖 Spring 啟動(dòng)時(shí)讀取應(yīng)用程序提供的Bean配置信息,并在Spring容器中生成一份相...
    Theriseof閱讀 2,832評(píng)論 1 24
  • 離鄉(xiāng)兩百日,有家不能回。 有如斷根草,日日漸枯萎。 心疲目無光,皮皺臉如灰。 苦盼十日期,笑顏故鄉(xiāng)歸。 ...
    森垚閱讀 193評(píng)論 0 1