02_Spring IOC(控制反轉(zhuǎn))

IOC的概念

  • IOC Inversion of Controller 控制反轉(zhuǎn)。
  • IOC 就是將對(duì)象的創(chuàng)建皿渗、初始化及銷毀交給 spring 容器來(lái)處理成榜。

ApplicationContext 與 BeanFactory 的關(guān)系

  1. ApplicationContext 是 BeanFactory 的子接口规求。
  2. BeanFactory 采用延遲加載的方案,在getBean時(shí)才會(huì)實(shí)例化Bean幽钢。
    • XmlBeanFactory
    public void test4() {
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        beanFactory.getBean("helloWorld");
    }
    // 經(jīng)過(guò)測(cè)試,BeanFactory在getBean時(shí)才實(shí)例化Bean傅是。
    
  3. ApplicationContext 在配置文件加載時(shí)匪燕,就會(huì)初始化Bean蕾羊,并且提供不同應(yīng)用層的實(shí)現(xiàn)。在開(kāi)發(fā)中我們一般使用 ApplicationContext 的實(shí)現(xiàn)類:
    • FileSystemXmlApplicationContext 根據(jù)文件路徑讀取xml文件
    public void test5() {
        // 根據(jù)系統(tǒng)文件路徑讀取xml文件
        ApplicationContext context = new FileSystemXmlApplicationContext("src/applicationContext.xml");
        context.getBean("helloWorld");
    }
    
    • ClassPathXmlApplicationContext 根據(jù)classpath路徑讀取xml文件
    public void test5() {
        // 根據(jù)classpath路徑讀取xml文件
        ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");
        context.getBean("helloWorld");
    }
    
    • WebApplicationContext web開(kāi)發(fā)中常用

Bean的實(shí)例化方式

  1. 無(wú)參構(gòu)造方法
    • 編寫(xiě)配置文件 applicationContext.xml
    <?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">
        <bean id="helloWorld" class="com.zhangquanli.spring.helloworld.HelloWorld"/>
    </beans>
    
    • 編寫(xiě)測(cè)試方法
    public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
        helloWorld.show();
    }
    
  2. 靜態(tài)工廠方法
    • 編寫(xiě)工廠類帽驯,在工廠類中提供一個(gè)靜態(tài)方法龟再,返回Bean對(duì)象
    public class HelloWorldFactory {
        public static HelloWorld getInstance() {
            return new HelloWorld();
        }
    }
    
    • 編寫(xiě)配置文件 applicationContext.xml
    <?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">
        <bean id="helloWorld2" class="com.zhangquanli.spring.helloworld.HelloWorldFactory" factory-method="getInstance"/>
    </beans>
    
    • 編寫(xiě)測(cè)試方法
    public void test2() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld2");
        helloWorld.show();
    }
    
  3. 實(shí)例工廠方法
    • 編寫(xiě)工廠類,在工廠類中提供一個(gè)非靜態(tài)方法尼变,返回Bean對(duì)象
    public class HelloWorldFactory2 {
        public HelloWorld getInstance() {
            return new HelloWorld();
        }
    }
    
    • 編寫(xiě)配置文件 applicationContext.xml
    <?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">
        <bean id="helloWorldFactory2" class="com.zhangquanli.spring.helloworld.HelloWorldFactory2"/>
        <bean id="helloWorld3" factory-bean="helloWorldFactory2" factory-method="getInstance"/>
    </beans>
    
    • 編寫(xiě)測(cè)試方法
    public void test3() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld3");
        helloWorld.show();
    }
    

Bean的別名

  1. 編寫(xiě)配置文件
<?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">
    <bean id="helloWorld" class="com.zhangquanli.spring.helloworld.HelloWorld"/>
    <alias name="helloWorld" alias="a"/>
    <alias name="helloWorld" alias="b"/>
    <alias name="helloWorld" alias="c"/>
</beans>
  1. 編寫(xiě)測(cè)試方法
public void testAlias() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    HelloWorld a = (HelloWorld) context.getBean("a");
    a.show();
    HelloWorld b = (HelloWorld) context.getBean("b");
    b.show();
    HelloWorld c = (HelloWorld) context.getBean("c");
    c.show();
}

Bean的創(chuàng)建時(shí)機(jī)

  1. 在 bean 標(biāo)簽中有 lazy-init 屬性
    • default利凑,相當(dāng)于 false,在 spring 容器啟動(dòng)的時(shí)候創(chuàng)建對(duì)象嫌术。
    • true哀澈,在 context.getBean 時(shí)創(chuàng)建對(duì)象。
    • false度气,在 spring 容器啟動(dòng)的時(shí)候創(chuàng)建對(duì)象割按。
  2. lazy-init 屬性的意義
    • 如果把 lazy-init 設(shè)置為 true ,則當(dāng) spring 容器啟動(dòng)的時(shí)候磷籍,檢測(cè)不到任何錯(cuò)誤适荣,這樣會(huì)存在很大的安全性隱患。所以一般情況應(yīng)該設(shè)置 lazy-init 為 false/default 院领。
    • 但是如果一個(gè)bean中有一個(gè)屬性束凑,該屬性含有大量的數(shù)據(jù),這個(gè)時(shí)候不希望該bean過(guò)早的停留在內(nèi)存中栅盲,這個(gè)時(shí)候需要用到 lazy-int 為 true 汪诉。

Bean的作用域

  1. 在 bean 標(biāo)簽中有 scope 屬性,用于描述 bean 的作用域谈秫。
    • singleton扒寄,單例模式,代表在 spring ioc 容器中只有一個(gè) bean 實(shí)例拟烫。(默認(rèn)的scope)
    • prototype该编,多例模式,每一次從 spring ioc 容器中獲取硕淑,都會(huì)返回一個(gè)新實(shí)例课竣。
    • request,用在web開(kāi)發(fā)中置媳,通過(guò) request.setAttribute() 將 bean 對(duì)象存儲(chǔ)到request域中于樟。
    • session,用在web開(kāi)發(fā)中拇囊,通過(guò) session.setAttribute() 將 Bean 對(duì)象存儲(chǔ)到session域中迂曲。
  2. 默認(rèn)情況下,放入spring容器中的bean是單例的寥袭。
    • 將來(lái)service層和dao層所有的類將放入到spring容器中路捧,所以默認(rèn)情況下這兩個(gè)層的類的實(shí)例都是單例的关霸,所以不能把數(shù)據(jù)聲明到屬性中。如果聲明到屬性中杰扫,將會(huì)成為共享的队寇,涉及到線程安全問(wèn)題。

創(chuàng)建時(shí)機(jī)和作用域的結(jié)合

  1. <font color="red">scope="prototype" lazy-init="true"</font> 在 context.getBean 時(shí)創(chuàng)建對(duì)象
  2. <font color="red">scope="prototype" lazy-init="false"</font> 在 context.getBean 時(shí)創(chuàng)建對(duì)象章姓,lazy-init為false失效英上。即在 scope 為 prototype 時(shí),始終在 context.getBean 時(shí)創(chuàng)建對(duì)象
  3. scope為singleton時(shí)啤覆,是默認(rèn)情況苍日。

Bean的生命周期

  1. Bean的生命周期方法
    • instantiate bean 實(shí)例化 Bean 對(duì)象
    • populate properties 給 Bean 對(duì)象注入屬性
    • 如果 Bean 實(shí)現(xiàn) BeanNameAware 執(zhí)行 setBeanName
    • 如果 Bean 實(shí)現(xiàn) BeanFactoryAware 或 ApplicationContextAware 執(zhí)行 setBeanFactory 或 setApplicationContext
    • 如果存在類實(shí)現(xiàn) BeanPostProcessor 執(zhí)行postProcessBeforeInitialization
    • 如果 Bean 實(shí)現(xiàn) InitializingBean 執(zhí)行 afterPropertiesSet
    • 調(diào)用 Bean 中自定義的 init-method 方法
    • 如果存在類實(shí)現(xiàn) BeanPostProcessor 執(zhí)行postProcessorAfterInitialization
    • 執(zhí)行業(yè)務(wù)邏輯代碼
    • 如果 Bean 實(shí)現(xiàn) DisposableBean 執(zhí)行 destroy
    • 調(diào)用 Bean 中自定義的 destroy-method 方法
  2. Bean的生命周期測(cè)試代碼
    • HelloWorld.java
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    public class HelloWorld implements BeanNameAware,ApplicationContextAware,InitializingBean,DisposableBean {
    
        private String info;
    
        public String getInfo() {
            return info;
        }
    
        public void setInfo(String info) {
            this.info = info;
        }
    
        public HelloWorld() {
            System.out.println("第一步:instantiate bean 實(shí)例化Bean對(duì)象");
        }
    
        public void show() {
            System.out.println("第九步:show time 執(zhí)行業(yè)務(wù)邏輯代碼");
        }
    
        public void myInit() {
            System.out.println("第七步:調(diào)用 Bean 中自定義的 init-method 方法");
        }
    
        public void myDestroy() {
            System.out.println("第十一步:調(diào)用 Bean 中自定義的 destroy-method 方法");
        }
    
        @Override
        public void setBeanName(String arg0) {
            System.out.println("第三步:如果 Bean 實(shí)現(xiàn) BeanNameAware 執(zhí)行 setBeanName" + info);
        }
    
        @Override
        public void setApplicationContext(ApplicationContext arg0) throws BeansException {
            System.out.println("第四步:如果 Bean 實(shí)現(xiàn) BeanFactoryAware 或 ApplicationContextAware 執(zhí)行 setBeanFactory 或 setApplicationContext");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("第六步:如果 Bean 實(shí)現(xiàn) InitializingBean 執(zhí)行 afterPropertiesSet");
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("第十步:如果 Bean 實(shí)現(xiàn) DisposableBean 執(zhí)行 destroy");
        }
    
    }
    
    • MyProcessor.java
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyProcessor implements BeanPostProcessor{
    
        @Override
        public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException {
            System.out.println("第八步:如果存在類實(shí)現(xiàn) BeanPostProcessor 執(zhí)行postProcessorAfterInitialization");
            return arg0;
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException {
            System.out.println("第五步:如果存在類實(shí)現(xiàn) BeanPostProcessor 執(zhí)行postProcessBeforeInitialization");
            return arg0;
        }
    
    }
    
    • applicationContext.xml
    <?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">
        
        <bean id="helloWorld" class="com.zhangquanli.spring.life.HelloWorld" init-method="myInit" destroy-method="myDestroy">
            <property name="info" value="你好啊"></property>
        </bean>
        <!-- 此類是針對(duì)所有其他bean類的 -->
        <bean id="myProcessor" class="com.zhangquanli.spring.life.MyProcessor"/>
    
    </beans>
    
    • HelloWorldTest
    import org.junit.Test;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class HelloWorldTest {
        @Test
        public void test1() {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
            helloWorld.show();
            context.close();
        }
    }
    
  3. Bean的生命周期的說(shuō)明
    • 第3步和第4步,是讓 Bean 了解 spring 容器窗声。
    • 第5步和第8步相恃,可以針對(duì)指定 的Bean 使用動(dòng)態(tài)代理進(jìn)行功能增強(qiáng)。
    • 第6步和第10步笨觅,可以實(shí)現(xiàn)指定的接口來(lái)完成 init 和 destroy 操作拦耐。
    • 在開(kāi)發(fā)中,一般不使用第6步和第10步见剩,因?yàn)榈?步和第11步也可以完成 init 和 destroy 的操作杀糯。同時(shí),第7步和第11步的初始化和銷毀操作無(wú)耦合苍苞,只需要在配置文件制定初始化和銷毀的方法固翰。
    <bean id="helloWorld" class="com.zhangquanli.spring.life.HelloWorld" init-method="myInit" destroy-method="myDestroy">
        <property name="info" value="你好啊"></property>
    </bean>
    
  4. Bean的生命周期的總結(jié)
    • 增強(qiáng) Bean 的功能,可以實(shí)現(xiàn) BeanPostProcessor 來(lái)完成羹呵。
    • 初始化和銷毀操作骂际,可以使用 bean 標(biāo)簽上的 init-method、destroy-method 方法來(lái)完成冈欢。
    • <font color="red">注意:destroy-method 只在 scope="singleton" 才有效果歉铝。</font>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市凑耻,隨后出現(xiàn)的幾起案子太示,更是在濱河造成了極大的恐慌,老刑警劉巖香浩,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件类缤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡弃衍,警方通過(guò)查閱死者的電腦和手機(jī)呀非,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)镜盯,“玉大人岸裙,你說(shuō)我怎么就攤上這事∷倮拢” “怎么了降允?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)艺糜。 經(jīng)常有香客問(wèn)我剧董,道長(zhǎng),這世上最難降的妖魔是什么破停? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任翅楼,我火速辦了婚禮,結(jié)果婚禮上真慢,老公的妹妹穿的比我還像新娘毅臊。我一直安慰自己,他們只是感情好黑界,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布管嬉。 她就那樣靜靜地躺著,像睡著了一般朗鸠。 火紅的嫁衣襯著肌膚如雪蚯撩。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天烛占,我揣著相機(jī)與錄音胎挎,去河邊找鬼。 笑死忆家,一個(gè)胖子當(dāng)著我的面吹牛呀癣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弦赖,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼项栏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蹬竖?” 一聲冷哼從身側(cè)響起沼沈,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎币厕,沒(méi)想到半個(gè)月后列另,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旦装,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年页衙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡店乐,死狀恐怖艰躺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情眨八,我是刑警寧澤腺兴,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站廉侧,受9級(jí)特大地震影響页响,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜段誊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一闰蚕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧连舍,春花似錦没陡、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至参滴,卻和暖如春强岸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砾赔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工蝌箍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人暴心。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓妓盲,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親专普。 傳聞我的和親對(duì)象是個(gè)殘疾皇子悯衬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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