Spring框架中的IOC容器及bean管理

什么是IOC容器叠穆?
IOC即反轉(zhuǎn)控制瘦材,創(chuàng)建對象的權(quán)利交給容器來完成期奔,而程序要做的僅僅是使用對象侧馅。
Spring 容器是 Spring 框架的核心。容器將創(chuàng)建對象呐萌,把它們連接在一起馁痴,配置它們,并管理他們的整個生命周期從創(chuàng)建到銷毀肺孤。Spring 容器使用依賴注入(DI)來管理組成一個應(yīng)用程序的組件罗晕。這些對象被稱為 Spring Beans
Spring中的IOC容器的使用
如何在IOC容器中配置bean?
使用標簽來將一個類配置到IOC容器中

<!-- bean標簽:用來向IOC容器配置一個bean
    id:用來唯一標識這個bean對象
    class:指明該bean對象的全類名
    property標簽:向bean中注入屬性
 -->
<bean id="student" class="com.cn.cmc.beans.Student" >
    <property name="name" value="葉清逸"></property>
</bean>

如何獲取IOC容器赠堵?
Spring提供兩種IOC容器:
ApplicationContext容器
BeanFactory容器(已廢棄)
獲取ApplicationContext容器
/**
* ApplicationContext代表IOC容器
* ClassPathXmlApplicationContext從類路徑下讀取配置文件
* FileSystemXmlApplicationContext從文件系統(tǒng)路徑下讀取配置文件
* WebXmlApplicationContext:在web 應(yīng)用程序的范圍內(nèi)加載在 XML 文件中已被定義的 bean小渊。
*/
ApplicationContext context = new FileSystemXmlApplicationContext("config/beans.xml") ;

獲取BeanFactory容器(已廢棄)
/**

  • XmlBeanFactory生成工廠bean
  • ClassPathResource加載配置文件
    */
    XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("config/beans.xml")) ;

bean管理
從IOC容器中獲取bean
方式一:通過id獲取bean
/方式一:通過id獲取bean/
Student student = context.getBean(Student.class);
System.out.println(student.getName());

方式二:通過.class獲取bean
/方式二:通過.class文件獲取bean/
Student s = (Student)context.getBean("student") ;
System.out.println(s.getName());

方式三:通過工廠方法來獲取bean
靜態(tài)工廠方法
方法類

package com.cn.cmc.beans;

import java.util.HashMap;
import java.util.Map;

public class StaticStudentFactory {
    private static Map<String,Student> map ;
    static {
        map = new HashMap<String, Student>();
        map.put("葉清逸", new Student(100001,"葉清逸",'M',25)) ;
        map.put("張三", new Student(100002,"張三",'F',22)) ;
    }
    /*通過靜態(tài)方法獲取bean的實例*/
    static Student getBean(String name){
        return map.get(name) ;
    }
}

xml中的配置:

<!-- 通過靜態(tài)工廠方法來獲取實例
    factory-method:對應(yīng)工廠中配置的獲取bean的方法名
    constructor-arg:對用獲取bean方法傳入的參數(shù)
 -->
<bean id="student1" class="com.cn.cmc.beans.StaticStudentFactory" factory-method="getBean">
    <constructor-arg value="葉清逸"></constructor-arg>
</bean>

bean的屬性注入
方式一:屬性注入(通過setter方法)

<property name="name" value="葉清逸"></property>

方式二:構(gòu)造方法注入

<bean id="student" class="com.cn.cmc.beans.Student" >
    <!-- constructor-arg標簽:使用構(gòu)造方法來傳入?yún)?shù)
        name:對應(yīng)傳入屬性的名
        value:對應(yīng)傳入屬性的值
        index:對應(yīng)傳入屬性在類中的位置
        type:對應(yīng)傳入屬性在類中的類型
        ref:bean之間的引用

        注:index和type主要是為了解決傳入時產(chǎn)生歧義的問題,可以不寫
            在類中要有對應(yīng)的構(gòu)造方法茫叭,可以沒有setter方法
     -->
    <constructor-arg name="id" value="100001"></constructor-arg>
    <constructor-arg name="name">
        <value>葉清逸</value>
    </constructor-arg>
    <constructor-arg name="sex" value="M" index="2" type="char"></constructor-arg>
    <constructor-arg name="age" value="25"></constructor-arg>
</bean>

注:若傳入值有特殊字符酬屉,可以使用<[CDATA[]]包裹起來>

注入的一些其他細節(jié)
使用ref屬性引用其他bean

<bean id="student" class="com.cn.cmc.beans.Student" >
<constructor-arg name="id" value="100001"></constructor-arg>
<constructor-arg name="name">
    <value>葉清逸</value>
</constructor-arg>
<constructor-arg name="sex" value="M" index="2" type="char"></constructor-arg>
<constructor-arg name="age" value="25"></constructor-arg>
<!-- ref:引用其他已配置的bean -->
<constructor-arg name="phone" ref="phone"></constructor-arg>
</bean>

<bean id="phone" class="com.cn.cmc.beans.Phone">
    <property name="id" value="200001"></property>
    <property name="name" value="蘋果手機"></property>
</bean>

屬性內(nèi)配置內(nèi)部bean

<bean id="student" class="com.cn.cmc.beans.Student" >
    <constructor-arg name="id" value="100001"></constructor-arg>
    <constructor-arg name="name">
        <value>葉清逸</value>
    </constructor-arg>
    <constructor-arg name="sex" value="M" index="2" type="char"></constructor-arg>
    <constructor-arg name="age" value="25"></constructor-arg>
    <!-- ref:引用其他已配置的bean -->
    <constructor-arg name="phone">
        <bean class="com.cn.cmc.beans.Phone">
            <property name="id" value="200001"></property>
            <property name="name" value="蘋果手機"></property>
        </bean>
    </constructor-arg>
</bean>

注:內(nèi)部 bean不能被外部引用

配置級聯(lián)屬性

<bean id="student" class="com.cn.cmc.beans.Student" >
    <constructor-arg name="id" value="100001"></constructor-arg>
    <constructor-arg name="name">
        <value>葉清逸</value>
    </constructor-arg>
    <constructor-arg name="sex" value="M" index="2" type="char"></constructor-arg>
    <constructor-arg name="age" value="25"></constructor-arg>
    <!-- ref:引用其他已配置的bean -->
    <constructor-arg name="phone" ref="phone"></constructor-arg>
    <!-- 配置級聯(lián)屬性(要有對應(yīng)的bean和setter方法) -->
    <property name="phone.name" value="小米手機"></property>
</bean>

<bean id="phone" class="com.cn.cmc.beans.Phone">
    <property name="id" value="200001"></property>
    <property name="name" value="蘋果手機"></property>
</bean>

Collection的注入(set,map,list,property)

<property name="phoneSet">
    <!-- 使用<set>標簽來注入set -->
    <set>
    <!-- ref標簽:表示關(guān)聯(lián)的bean
        bean:已配置的bean的id -->
        <ref bean="phone1"/>
        <ref bean="phone2"/>
        <!-- 也可以注入內(nèi)部bean -->
        <bean class="com.cn.cmc.beans.Phone">
            <property name="id" value="200003"></property>
            <property name="name" value="華為手機"></property>
        </bean>
    </set>
</property>

<property name="phoneList">
    <!-- 使用<list>標簽來注入list -->
    <list>
    <!-- ref標簽:表示關(guān)聯(lián)的bean
        bean:已配置的bean的id 
    -->
        <ref bean="phone1"/>
        <ref bean="phone2"/>
        <!-- 也可以注入內(nèi)部bean -->
        <bean class="com.cn.cmc.beans.Phone">
            <property name="id" value="200003"></property>
            <property name="name" value="華為手機"></property>
        </bean>
        <ref bean="phone1"/>
        <ref bean="phone2"/>
    </list>
</property>
<property name="phoneMap">
    <!-- 使用<map>標簽來注入map -->
    <map>
        <!-- entry標簽:表示map中的元素
            key:注入的鍵
            value:注入的值
            key-ref:注入鍵的關(guān)聯(lián)bean的id
            value-ref:祝福值關(guān)聯(lián)bean的id
         -->
        <entry key="1" value-ref="phone1"></entry>
        <entry key="2" value-ref="phone2"></entry>
        <!-- 也可以使用注入內(nèi)部類的方式 -->
        <entry key="3">
            <bean class="com.cn.cmc.beans.Phone">
                <property name="id" value="200003"></property>
                <property name="name" value="華為手機"></property>
            </bean>
        </entry>
    </map>
</property>
<property name="phoneProp">
    <!-- 使用prop配置property屬性 -->
    <props>
        <prop key="1">cmc</prop>
        <prop key="2">root</prop>
    </props>
</property>

使用util標簽配置共享的bean

 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/util
                        http://www.springframework.org/schema/util/spring-util-2.0.xsd">

<!-- 使用util標簽來配置共享的bean -->
    <util:list id="phonelist">
        <ref bean="phone1"/>
        <ref bean="phone2"/>
    </util:list>

使用p命名空間配置bean

    <bean id="student2" class="com.cn.cmc.beans.Student" p:id="100002" p:name="張三"
            p:age="22" p:sex="F"></bean>

bean的自動裝配
IOC容器可以自動裝配bean,我們要做的僅僅是在bean的autowire屬性中配置裝配方式:

byType 按類型自動裝配
byName 按名稱自動裝配
byConstructor 按構(gòu)造器自動裝配(不推薦)
byName 按名稱自動裝配bean
<bean id="student2" class="com.cn.cmc.beans.Student" p:id="100002" p:name="張三"

            p:age="22" p:sex="F" autowire="byName"></bean>

注:通過byName自動裝配杂靶,屬性名必須和bean中定義的屬性名一致梆惯,否則裝配為空

byType 按類型自動裝配bean

<bean id="student3" class="com.cn.cmc.beans.Student" p:id="100002" p:name="張三"
            p:age="22" p:sex="F" autowire="byType"></bean>

注:通過byType自動裝配酱鸭,已配置的 bean中只有一個該類型的 bean時會裝配成功,有多個時會報錯

bean之間的關(guān)系(繼承垛吗,依賴)
bean之間的關(guān)系有:

繼承:子bean會繼承父bean中的屬性
依賴:實例化bean時要配置依賴的bean凹髓,否則無法實例化該bean
繼承與依賴的例子

 <bean id="phone" class="com.cn.cmc.beans.Phone"
        p:id="200001" p:name="蘋果手機"></bean>
 <bean id="student" class="com.cn.cmc.beans.Student" 
        p:id="100003" p:name="李四" p:age="24" p:sex="M" abstract="true"></bean>
 <bean id="student1" class="com.cn.cmc.beans.Student"
        parent="student" p:name="王五" p:id="100004" p:phone-ref="phone" 
        depends-on="phone"></bean>

bean的作用域配置
Spring中可以使用scope屬性來配置bean的作用域:

singleton:單例,在初始化配置文件時生成單例bean對象
prototype:原型的怯屉,在初始化配置文件時不生成bean對象蔚舀,使用時返回不同的bean對象
request:web環(huán)境下每一個request請求都會返回一個不同的bean,只在本次請求中有效
session:web環(huán)境下每一個request請求都會返回一個不同的bean锨络,在session中有效

 <bean id="student" class="com.cn.cmc.beans.Student" 
        p:id="100001" p:name="葉清逸" p:age="25" p:sex="M" scope="singleton"></bean>

IOC容器中bean的生命周期
通過init-method和destroy-method
先看例子

<bean id="student" class="com.cn.cmc.beans.Student" 
        p:id="100001" p:name="葉清逸" p:age="25" p:sex="M" scope="singleton"
        init-method="init" destroy-method="destroy"></bean>

執(zhí)行結(jié)果:
七月 08, 2018 4:21:13 下午 org.springframework.context.support.FileSystemXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@11028347: startup date [Sun Jul 08 16:21:13 CST 2018]; root of context hierarchy
七月 08, 2018 4:21:13 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from file [C:\Users\Mr_Chuan\workspace\HelloSpring\config\bean-cycle.xml]
bean初始化...
七月 08, 2018 4:21:14 下午 org.springframework.context.support.FileSystemXmlApplicationContext doClose
信息: Closing org.springframework.context.support.FileSystemXmlApplicationContext@11028347: startup date [Sun Jul 08 16:21:13 CST 2018]; root of context hierarchy
bean銷毀...

由上例可以看出bean的生命周期為

  1. 通過構(gòu)造方法生成bean的實例
  2. 為bean注入屬性
  3. 調(diào)用初始化方法
  4. bean的使用
  5. IOC容器關(guān)閉時赌躺,調(diào)用銷毀方法

通過bean的后置處理器BeanPostProcessor
新建處理器類實現(xiàn)BeanPostProcessor接口

package com.cn.cmc.test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

    /**
     * postProcessBeforeInitialization在init-method之后調(diào)用
     * 參數(shù)arg0表示實例bean本身
     * 參數(shù)arg1表示IOC容器中已配置bean的名字
     * 返回值實際上為返回給用戶的bean
     */
    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessAfterInitialization"+arg0+" "+arg1);
        return arg0;
    }
    /**
     * postProcessAfterInitialization在init-method之前調(diào)用
     */
    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessBeforeInitialization"+arg0+" "+arg1);
        return arg0;
    }
}

在配置文件中配置BeanPostProcessor
<bean class="com.cn.cmc.test.MyBeanPostProcessor"></bean>
1
由上例可以看出加了后置處理器之后執(zhí)行流程為:

  1. 通過構(gòu)造方法生成bean的實例
  2. 為bean注入屬性
  3. 將bean傳給后置處理器的postProcessBeforeInitialization方法
  4. 調(diào)用初始化方法
  5. 將bean傳給后置處理器的postProcessAfterInitialization方法
  6. bean的使用
  7. IOC容器關(guān)閉時,調(diào)用銷毀方法
    ————————————————
    版權(quán)聲明:本文為CSDN博主「葉清逸」的原創(chuàng)文章羡儿,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議礼患,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
    原文鏈接:https://blog.csdn.net/u013634252/article/details/80946404
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掠归,一起剝皮案震驚了整個濱河市缅叠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌虏冻,老刑警劉巖肤粱,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異厨相,居然都是意外死亡领曼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門蛮穿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庶骄,“玉大人,你說我怎么就攤上這事绪撵∑耙觯” “怎么了祝蝠?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵音诈,是天一觀的道長。 經(jīng)常有香客問我绎狭,道長细溅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任儡嘶,我火速辦了婚禮喇聊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蹦狂。我一直安慰自己誓篱,他們只是感情好朋贬,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窜骄,像睡著了一般锦募。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邻遏,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天糠亩,我揣著相機與錄音,去河邊找鬼准验。 笑死赎线,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的糊饱。 我是一名探鬼主播垂寥,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼另锋!你這毒婦竟也來了矫废?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤砰蠢,失蹤者是張志新(化名)和其女友劉穎蓖扑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體台舱,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡律杠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了竞惋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柜去。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拆宛,靈堂內(nèi)的尸體忽然破棺而出嗓奢,到底是詐尸還是另有隱情,我是刑警寧澤浑厚,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布股耽,位于F島的核電站,受9級特大地震影響钳幅,放射性物質(zhì)發(fā)生泄漏物蝙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一敢艰、第九天 我趴在偏房一處隱蔽的房頂上張望诬乞。 院中可真熱鬧,春花似錦、人聲如沸震嫉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽票堵。三九已至柜砾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間换衬,已是汗流浹背痰驱。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瞳浦,地道東北人担映。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像叫潦,于是被迫代替她去往敵國和親蝇完。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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