天天看點

Spring學習筆記(一)IOC與Spring基礎xml配置1. IOC與DI2. IOC的發展曆程3. Spring容器4. 注入方式5. 配置細節6. 免XML的JAVA類配置

1. IOC與DI

IOC(Inversion of Control):控制反轉

DI(Dependency Injection):依賴注入

“控制反轉”和“依賴注入”其實是同一個概念:

改變由調用者建立被調用者的過程。被調用者依賴Spring容器注入到調用者中。

之是以出現兩個名詞是因為“控制反轉”比較難懂,聽者不明是以,是以有了更形象的“依賴注入”。

2. IOC的發展曆程

Spring學習筆記(一)IOC與Spring基礎xml配置1. IOC與DI2. IOC的發展曆程3. Spring容器4. 注入方式5. 配置細節6. 免XML的JAVA類配置

3. Spring容器

簡單說,就是Spring中生成“Bean”的工廠,并管理“Bean”的生命周期。Spring的配置檔案說到底就是“Bean”的配置。

“Bean”是Spring管理的基本機關,不僅僅指簡單的POJO類,元件也是“Bean”,例如資料源、事務管理器,Hibernate的SessionFactory。

Spring中内置了兩種基礎DI容器:

BeanFactory

ApplicationContext

ApplicationContext

繼承了

BeanFactory

的所有特性。關系如下圖:

Spring學習筆記(一)IOC與Spring基礎xml配置1. IOC與DI2. IOC的發展曆程3. Spring容器4. 注入方式5. 配置細節6. 免XML的JAVA類配置

BeanFactory

應用與記憶體、CPU資源受限的場合,一般情況下優先使用

ApplicationContext

,因為它除了擁有

BeanFactory

支援的所有功能,還可以:

  1. 載入多個配置檔案
  2. 提供國際化支援
  3. 事件機制
  4. 預設初始化所有的singleton Bean(

    BeanFactory

    則不會)

常用的

ApplicationContext

的子類如下圖:

Spring學習筆記(一)IOC與Spring基礎xml配置1. IOC與DI2. IOC的發展曆程3. Spring容器4. 注入方式5. 配置細節6. 免XML的JAVA類配置
  • XmlWebApplicationContext:面向Web應用
  • AnnotationConfigApplicationContext:基于注解存儲DI中繼資料
  • XmlPortlerApplicationContext:面向Portal應用
  • ClassPathXmlApplicationContext、FileSystemXmlApplicationContext:适用于各種場景

4. 注入方式

Spring的注入方式有三種:設值注入、構造器注入、工廠注入。

設定注入和構造器注入

實體類:

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

    public Person(Axe axe, String name) {
        System.out.println("Person 的帶參構造方法");
        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标簽更友善的配置屬性 -->
<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 表示你這個元件的名字,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>
        <!--構造注入,index為形參的位置,從0開始,ref為注入bean的id -->
        <constructor-arg ref="stoneaxe" index="0" /> 
        <constructor-arg value="wsz" index="1" />
    </bean>

    <!--其餘實體Bean-->
    <bean id="ironaxe" class="test.wsz.spring.bean.IronAxe" />
    <bean id="stoneaxe" class="test.wsz.spring.bean.StoneAxe" />

</beans>
           

從配置的注釋可以知道“設定注入”和“構造器注入”的配置方法。

  • “設定注入”會調用成員變量的

    setXXX

    方法。
  • “構造器注入”會調用類對應的構造方法。

測試代碼:

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

工廠方式注入

工廠方式注入有好幾種,這裡隻舉“靜态工廠注入”和“工廠Bean的例子”

  • 靜态工廠注入

    先建立一個工廠類:

/**
 * 靜态簡單工程類
 */
public class AxeFactory {
    /**
     * 擷取産品的方法,根據形參傳回不同的産品
     */
    public static Axe getAxe(String type) {
        if("stone".equals(type))
            return new StoneAxe();

        else if("iron".equals(type))
            return new IronAxe();

        return new StoneAxe();
    }
}
           

再修改之前的類當成産品類:

public class StoneAxe implements Axe {
    private String test;


    public StoneAxe() {
        System.out.println("調用StoneAxe的無參構造方法");
    }

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

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

再在xml檔案中進行對應的配置:

<!--靜态工廠類擷取Bean,class為工廠類;factory-method為工廠擷取方法-->
    <bean id="stone" class="test.wsz.spring.factory.AxeFactory" factory-method="getAxe">
        <!--設定傳入工廠類擷取産品方法形參的值-->
        <constructor-arg value="stone"/> 
        <!--設定注入産品Bean的屬性-->
        <property name="test" value="哈哈,"></property>
    </bean>
           

根據配置我們可以知道,現在設定的工廠類傳回

StoneAxe

,我們進行測試:

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

輸出:

哈哈,石斧砍柴很慢
           
  • 工廠Bean注入

    這種方式配置比較簡單。隻需要建立一個實作了Spring工廠接口的工廠類,再将這個工廠類配置在

    <Beans />

    中即可。

工廠類,需實作接口的三個方法:

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

xml配置:

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

值得注意的是,雖然

<Bean />

中配置的好像是工廠類,但實作了Spring工廠接口的該類,最終

getBean()

時傳回的是對應的産品類。

測試代碼:

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

輸出:

null石斧砍柴很慢
           

5. 配置細節

Spring的配置的參數太多,這裡隻總結一些常用的。複雜的等用到時再看書就行。

<bean />

中的常用配置

  • scope:

    Bean的作用域,有5種:

    • singleton:單例模式,即整個容器裡面該Bean執行個體隻有一個,預設
    • prototype:原型模式,每次

      getBean

      擷取的是一個新建立的對象
    • request:每個HTTP請求,産生一個執行個體
    • session:每個HTTP session,産生一個執行個體
    • global session:每個全局的HTTP session,産生一個執行個體
  • lazy-init:

    懶加載,當使用使用

    ApplicationContext

    時,會自動初始化所有的

    singleton

    的“Bean”(“Bean”預設是

    singleton

    )。設定懶加載即不自動初始化這個類。
  • autowire:

    自動注入。即你不用在配置中設定成員變量的注入。設定為

    byType

    時,會自動比對依賴類型相同的Bean,若有多個類型相同的會抛出異常。設定為

    byName

    時,會查找id名與屬性名相等的Bean。
  • init-method:

    指定Bean依賴關系設定完畢後執行的方法。另外一種實作方式是讓Bean類實作

    InitializingBean

    接口
  • destory-method:

    指定Bean銷毀之前執行的方法。另外一種實作方式是讓Bean類實作

    DisposableBean

    接口
  • p名稱空間:

    可以看作一個文法糖,在

    <beans />

    中添加:

即可更簡單的設定注入:

<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類配置

這個其實應用場景比較少,畢竟單純用Java類完成複雜的Spring配置還是比較困難的。下面簡單給個例子:

@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配置。有興趣的朋友可以自行百度。

本文總結于

《瘋狂JavaEE》的第七章《Spring的基本用法》