Spring 學(xué)習(xí)筆記(一)IOC

1. IOC(Inversion of Control)與DI(Dependency Injection)

“控制反轉(zhuǎn)”“依賴注入”其實(shí)是同一個(gè)概念:
改變由調(diào)用者創(chuàng)建被調(diào)用者的過程。被調(diào)用者依賴Spring容器注入到調(diào)用者中眉睹。
之所以出現(xiàn)兩個(gè)名詞是因?yàn)?strong>“控制反轉(zhuǎn)”比較難懂许起,聽者不明所以鹿寻,所以有了更形象的“依賴注入”财搁。

2. IOC的發(fā)展歷程

3. Spring容器

簡單說,就是Spring中生成“Bean”的工廠蜓洪,并管理“Bean”的生命周期裳仆。Spring的配置文件說到底就是“Bean”的配置纯丸。

“Bean”是Spring管理的基本單位滑凉,不僅僅指簡單的POJO類,組件也是“Bean”,例如數(shù)據(jù)源、事務(wù)管理器行冰,Hibernate的SessionFactory邻吞。

Spring中內(nèi)置了兩種基礎(chǔ)DI容器:BeanFactoryApplicationContext瘦癌。
ApplicationContext繼承了BeanFactory的所有特性。關(guān)系如下圖:


BeanFactory應(yīng)用與內(nèi)存跷敬、CPU資源受限的場合讯私,一般情況下優(yōu)先使用ApplicationContext,因?yàn)樗藫碛?code>BeanFactory支持的所有功能西傀,還可以:

  1. 載入多個(gè)配置文件
  2. 提供國際化支持
  3. 事件機(jī)制
  4. 默認(rèn)初始化所有的singleton BeanBeanFactory則不會)

常用的ApplicationContext的子類如下圖:

  • XmlWebApplicationContext:面向Web應(yīng)用
  • AnnotationConfigApplicationContext:基于注解存儲DI元數(shù)據(jù)
  • XmlPortlerApplicationContext:面向Portal應(yīng)用
  • ClassPathXmlApplicationContext斤寇、FileSystemXmlApplicationContext:適用于各種場景

4. 注入方式

Spring的注入方式有三種:設(shè)值注入、構(gòu)造器注入拥褂、工廠注入娘锁。

設(shè)置注入和構(gòu)造器注入

實(shí)體類:

public class Person{
    public String name;
    private Axe axe;

    public Person(Axe axe, String name) {
        System.out.println("Person 的帶參構(gòu)造方法");
        this.axe = axe;
        this.name = name;
    }
    /**
     * 砍柴
     */
    public void choopWood() {
        if(axe!=null){
            axe.useAxe();           
        }
    }

    public void info() {
        System.out.println("This person's name is " + name);
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAxe(Axe axe) {
        this.axe = axe;

    }

}

注入類:

public interface Axe {
    
    public void useAxe();
}

public class StoneAxe implements Axe {

    public void useAxe() {
        System.out.println(test + "石斧砍柴很慢");
    }
}

public class IronAxe implements Axe{

    public void useAxe() {
        System.out.println("鐵斧砍柴很快");
    }

}

Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!--spring配置文件的根元素,使用spring-beans-3.0.xsd語義約束(.xsd都是語言約束文件)
    xmlns:p配置可使用p標(biāo)簽更方便的配置屬性 -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
     xmlns:p="http://www.springframework.org/schema/p"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- id 表示你這個(gè)組件的名字饺鹃,class表示組件類莫秆;autowire為是否自動加載; lazy-init為是否懶加載悔详,即applicationContext容器啟動不自動加載 -->
    <bean id="person" class="test.wsz.spring.bean.Person" lazy-init="true" autowire="byType" >
        <!--自定義set注入,name 為成員變量名稱镊屎,value為自定義的值 -->
        <property name="name" value="wsz"></property>
        <!--引用set注入,name 為成員變量名稱,ref為注入bean的id -->
        <property name="axe" ref="ironaxe"></property>
        <!--構(gòu)造注入,index為形參的位置茄螃,從0開始缝驳,ref為注入bean的id -->
        <constructor-arg ref="stoneaxe" index="0" /> 
        <constructor-arg value="wsz" index="1" />
    </bean>

    <!--其余實(shí)體Bean-->
    <bean id="ironaxe" class="test.wsz.spring.bean.IronAxe" />
    <bean id="stoneaxe" class="test.wsz.spring.bean.StoneAxe" />
    
</beans>

從配置的注釋可以知道“設(shè)置注入”和“構(gòu)造器注入”的配置方法。

  • “設(shè)置注入”會調(diào)用成員變量的setXXX方法责蝠。
  • “構(gòu)造器注入”會調(diào)用類對應(yīng)的構(gòu)造方法党巾。

測試代碼:

ApplicationContext context=new ClassPathXmlApplicationContext("config/spring-config.xml");
Person person=context.getBean("person",Person.class);
person.info();
person.choopWood();

工廠方式注入

工廠方式注入有好幾種,這里只舉“靜態(tài)工廠注入”和“工廠Bean的例子”

  • 靜態(tài)工廠注入

先創(chuàng)建一個(gè)工廠類:

/**
 * 靜態(tài)簡單工程類
 */
public class AxeFactory {
    /**
     * 獲取產(chǎn)品的方法霜医,根據(jù)形參返回不同的產(chǎn)品
     */
    public static Axe getAxe(String type) {
        if("stone".equals(type))
            return new StoneAxe();
        
        else if("iron".equals(type))
            return new IronAxe();
        
        return new StoneAxe();
    }
}

再修改之前的類當(dāng)成產(chǎn)品類:

public class StoneAxe implements Axe {
    private String test;

    
    public StoneAxe() {
        System.out.println("調(diào)用StoneAxe的無參構(gòu)造方法");
    }

    public void useAxe() {
        System.out.println(test + "石斧砍柴很慢");
    }

    public void setTest(String test) {
        this.test = test;
    }
}

再在xml文件中進(jìn)行對應(yīng)的配置:

<!--靜態(tài)工廠類獲取Bean,class為工廠類齿拂;factory-method為工廠獲取方法-->
    <bean id="stone" class="test.wsz.spring.factory.AxeFactory" factory-method="getAxe">
        <!--設(shè)置傳入工廠類獲取產(chǎn)品方法形參的值-->
        <constructor-arg value="stone"/> 
        <!--設(shè)置注入產(chǎn)品Bean的屬性-->
        <property name="test" value="哈哈,"></property>
    </bean>

根據(jù)配置我們可以知道肴敛,現(xiàn)在設(shè)置的工廠類返回StoneAxe署海,我們進(jìn)行測試:

Axe axe=context.getBean("stone",Axe.class);
axe.useAxe();

輸出:

哈哈,石斧砍柴很慢
  • 工廠Bean注入
    這種方式配置比較簡單医男。只需要創(chuàng)建一個(gè)實(shí)現(xiàn)了Spring工廠接口的工廠類砸狞,再將這個(gè)工廠類配置在<Beans />中即可。

工廠類镀梭,需實(shí)現(xiàn)接口的三個(gè)方法:

public class AxeBeanFactory implements FactoryBean<Axe>{
    Axe axe=null;
    /**
     * 返回產(chǎn)品
     */
    public Axe getObject() throws Exception {
        if(axe==null){
            axe=new StoneAxe();
        }
        return axe;
    }
    /**
     * 返回產(chǎn)品的類型
     */
    public Class<?> getObjectType() {
        return Axe.class;
    }
    /**
     * 是否單例
     */
    public boolean isSingleton() {
        return true;
    }
}

xml配置:

<!--容器中的工廠Bean-->
    <bean id="stonefactory" class="test.wsz.spring.factory.AxeBeanFactory" />

值得注意的是刀森,雖然<Bean />中配置的好像是工廠類,但實(shí)現(xiàn)了Spring工廠接口的該類报账,最終getBean()時(shí)返回的是對應(yīng)的產(chǎn)品類研底。

測試代碼:

Axe axe=context.getBean("stonefactory",Axe.class);
axe.useAxe();

輸出:

null石斧砍柴很慢

5. 配置細(xì)節(jié)

Spring的配置的參數(shù)太多埠偿,這里只總結(jié)一些常用的。復(fù)雜的等用到時(shí)再看書就行榜晦。

<bean />中的常用配置

  • scope
    Bean的作用域冠蒋,有5種:
  • singleton:單例模式,即整個(gè)容器里面該Bean實(shí)例只有一個(gè)乾胶,默認(rèn)
  • prototype:原型模式抖剿,每次getBean獲取的是一個(gè)新創(chuàng)建的對象
  • request:每個(gè)HTTP請求,產(chǎn)生一個(gè)實(shí)例
  • session:每個(gè)HTTP session识窿,產(chǎn)生一個(gè)實(shí)例
  • global session:每個(gè)全局的HTTP session斩郎,產(chǎn)生一個(gè)實(shí)例
  • lazy-init:
    懶加載,當(dāng)使用使用ApplicationContext時(shí)腕扶,會自動初始化所有的singleton的“Bean”(“Bean”默認(rèn)是singleton)孽拷。設(shè)置懶加載即不自動初始化這個(gè)類吨掌。
  • autowire:
    自動注入半抱。即你不用在配置中設(shè)定成員變量的注入。設(shè)置為byType時(shí)膜宋,會自動匹配依賴類型相同的Bean窿侈,若有多個(gè)類型相同的會拋出異常。設(shè)置為byName時(shí)秋茫,會查找id名與屬性名相等的Bean史简。
  • init-method:
    指定Bean依賴關(guān)系設(shè)置完畢后執(zhí)行的方法。另外一種實(shí)現(xiàn)方式是讓Bean類實(shí)現(xiàn)InitializingBean接口
  • destory-method
    指定Bean銷毀之前執(zhí)行的方法肛著。另外一種實(shí)現(xiàn)方式是讓Bean類實(shí)現(xiàn)DisposableBean接口
  • p名稱空間
    可以看作一個(gè)語法糖圆兵,在<beans />中添加:
xmlns:p="http://www.springframework.org/schema/p"  

即可更簡單的設(shè)置注入:

<bean id="person" class="test.wsz.spring.bean.Person"
      p:name="name" />

等效于

<bean id="person" class="test.wsz.spring.bean.Person" >
       <property name="name" value="wsz"></property>
</bean>

6. 免XML的JAVA類配置

這個(gè)其實(shí)應(yīng)用場景比較少,畢竟單純用Java類完成復(fù)雜的Spring配置還是比較困難的枢贿。下面簡單給個(gè)例子:

@Configuration
public class Config {
    
    @Value("王樹政") String personName;   //注入Bean的屬性中的值
    @Bean(name="person")
    public Person person(){
        Person p=new Person();
        p.setName(personName);
        p.setAxe(stoneAxe());
        return p;
    }
    @Bean(name="stoneAxe")
    public Axe stoneAxe() {
        Axe axe=new StoneAxe();
        
        return axe;
    }   
}

除了純粹的Java類配置殉农,還可以在xml中引用Java類配置,或者在Java類配置中引用xml配置局荚。有興趣的朋友可以自行百度超凳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市耀态,隨后出現(xiàn)的幾起案子轮傍,更是在濱河造成了極大的恐慌,老刑警劉巖首装,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件创夜,死亡現(xiàn)場離奇詭異,居然都是意外死亡仙逻,警方通過查閱死者的電腦和手機(jī)驰吓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門揍魂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人棚瘟,你說我怎么就攤上這事惭蟋」斗” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長览徒。 經(jīng)常有香客問我,道長碘勉,這世上最難降的妖魔是什么垄潮? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮章咧,結(jié)果婚禮上倦西,老公的妹妹穿的比我還像新娘。我一直安慰自己赁严,他們只是感情好扰柠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疼约,像睡著了一般卤档。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上程剥,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天劝枣,我揣著相機(jī)與錄音,去河邊找鬼织鲸。 笑死舔腾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的搂擦。 我是一名探鬼主播稳诚,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼盾饮!你這毒婦竟也來了采桃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤丘损,失蹤者是張志新(化名)和其女友劉穎普办,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徘钥,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衔蹲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舆驶。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡橱健,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沙廉,到底是詐尸還是另有隱情拘荡,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布撬陵,位于F島的核電站珊皿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏巨税。R本人自食惡果不足惜蟋定,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望草添。 院中可真熱鬧驶兜,春花似錦、人聲如沸远寸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽而晒。三九已至蝇狼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間倡怎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工贱枣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留监署,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓纽哥,卻偏偏與公主長得像钠乏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子春塌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理晓避,服務(wù)發(fā)現(xiàn),斷路器只壳,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,803評論 6 342
  • 文章作者:Tyan博客:noahsnail.com 3.4 Dependencies A typical ente...
    SnailTyan閱讀 4,151評論 2 7
  • 什么是Spring Spring是一個(gè)開源的Java EE開發(fā)框架俏拱。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,461評論 1 133
  • 按照自然規(guī)律來說惕艳,龍生龍搞隐,鳳生鳳驹愚。 林秋章 “爸,我不想上學(xué)了劣纲!”我對著坐在沙發(fā)上看...
    書怨閱讀 339評論 2 1