1. 程式人生 > >Spring4(3)——IOC控制反轉

Spring4(3)——IOC控制反轉

1.Spring裝配一個bean

在前一章中已涉及到此知識點,通俗的來講:在建立People實體之後,在beans.xml 中配置,然後在實現類中呼叫 beans.xml檔案,即裝配完成,呼叫預設的構造方法。

  1. 建立實體 (People.java) 類

    public class People {
    
        private int id;
        private String name;
        private int age;
        
        // 構造方法
        public People() {     
            super();
        }
        
        
    public People(int id, String name, int age) { super(); this.id = id; this.name = name; this.age = age; } }
  2. 配置beans.xml 檔案

    <bean id="people" class="com.java1234.entity.People"></bean>
  3. 呼叫beans.xml 檔案

    ApplicationContext ac=new
    ClassPathXmlApplicationContext("beans.xml");

     

2.依賴注入

  • 1. 屬性注入;
  • 2. 建構函式注入;(通過型別;通過索引;聯合使用)
  • 3. 工廠方法注入;(非靜態工廠,靜態工廠)
  • 4. 泛型依賴注入;(參考後面 Spring4 整合 Hibernate4 記錄)
        <!-- 裝配 -->
        <bean id="people" class="com.java1234.entity.People"></bean>
    
    
        <!--
    屬性注入--> <bean id="people2" class="com.java1234.entity.People"> <property name="id" value="1"></property> <property name="name" value="張三"></property> <property name="age" value="11"></property> </bean>

    <!-- 建構函式注入(通過型別)--> <bean id="people3" class="com.java1234.entity.People"> <constructor-arg type="int" value="2"></constructor-arg> <constructor-arg type="String" value="李四"></constructor-arg> <constructor-arg type="int" value="22"></constructor-arg> </bean> <!-- 建構函式注入(通過索引)--> <bean id="people4" class="com.java1234.entity.People"> <constructor-arg index="0" value="3"></constructor-arg> <constructor-arg index="1" value="王五"></constructor-arg> <constructor-arg index="2" value="55"></constructor-arg> </bean> <!-- 建構函式注入(型別索引聯合使用)--> <bean id="people5" class="com.java1234.entity.People"> <constructor-arg index="0" type="int" value="4"></constructor-arg> <constructor-arg index="1" type="String" value="招六"></constructor-arg> <constructor-arg index="2" type="int" value="66"></constructor-arg> </bean>

    <!-- 工廠方法注入(非靜態工廠)--> <bean id="peopleFactory" class="com.java1234.factory.PeopleFactory"></bean> <bean id="people6" factory-bean="peopleFactory" factory-method="createPeople"></bean> <!-- 工廠方法注入(靜態工廠)--> <bean id="people7" class="com.java1234.factory.PeopleFactory2" factory-method="createPeople"></bean>
    public class Test2 {
    
        public static void main(String[] args) {
            ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
            People people=(People)ac.getBean("people");
            System.out.println(people);
            
            // 屬性注入
            People people2=(People)ac.getBean("people2");
            System.out.println(people2);
            
            // 構造方法注入
            People people3=(People)ac.getBean("people3");
            System.out.println(people3);
            
            People people4=(People)ac.getBean("people4");
            System.out.println(people4);
            
            People people5=(People)ac.getBean("people5");
            System.out.println(people5);
            
            // 工廠方法注入
            People people6=(People)ac.getBean("people6");
            System.out.println(people6);
            
            People people7=(People)ac.getBean("people7");
            System.out.println(people7);
        }
    }

 

3.注入引數

  • 1. 基本型別值:參見上一節屬性注入

  • 2. 注入 bean;

    <!-- 在 people2 裡面注入 dog1 -->
    <bean id="dog1" class="com.java1234.entity.Dog">
      <property name="name" value="Jack"></property>
    </bean>
        
    <bean id="people2" class="com.java1234.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="張三"></property>
        <property name="age" value="11"></property>
        <property name="dog" ref="dog1"></property>  <!-- bean 注入 ,在 People.java 類中宣告 dog類-->
    </bean>
  • 3. 內部 bean;

    <bean id="people3" class="com.java1234.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="張三"></property>
        <property name="age" value="11"></property>
        <property name="dog">
            <bean class="com.java1234.entity.Dog">
                <property name="name" value="Tom"></property>
            </bean>
        </property>
    </bean>
  • 4. null 值;

    <bean id="people4" class="com.java1234.entity.People">
         <property name="id" value="1"></property>
         <property name="name" value="張三"></property>
         <property name="age" value="11"></property>
         <property name="dog">
             <null></null>
         </property>
    </bean>
  • 5. 級聯屬性;

    <bean id="people5" class="com.java1234.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="張三"></property>
        <property name="age" value="11"></property>
        <property name="dog.name" value="Jack2"></property> 
    <!-- 因為此處用到了dog的屬性,需要在宣告的時候new一個dog物件。( private Dog dog = new Dog(); ) --> </bean>
  • 6. 集合型別屬性;

    <bean id="people6" class="com.java1234.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="張三"></property>
        <property name="age" value="11"></property>
        <property name="dog" ref="dog1"></property>
        <property name="hobbies">
            <list>  <!-- list集合,可重複 -->
                <value>唱歌</value>
                <value>跳舞</value>
            </list>
        </property>
        <property name="loves">
            <set>  ·<!-- set集合,不可重複 -->
                <value>唱歌2</value>
                <value>跳舞2</value>
            </set>
        </property>
        <property name="works">
            <map>   <!-- Map鍵值對  -->
                <entry>
                    <key><value>上午</value></key>
                    <value>寫程式碼</value>
                </entry>
                <entry>
                    <key><value>下午</value></key>
                    <value>測試程式碼</value>
                </entry>
            </map>
        </property>
        <property name="addresses">
            <props>   <!-- props 輸入結果和Map類似,props 主要用於一些系統的配置-->
                <prop key="address1">aaaaa</prop>
                <prop key="address2">bbbbb</prop>
            </props>
        </property>
    </bean>
    private Dog dog;
    private List<String> hobbies=new ArrayList<String>();
    private Set<String> loves=new HashSet<String>();
    private Map<String,String> works=new HashMap<String,String>();
    private Properties addresses=new Properties();

     

4.自動裝配

通過配置 default-autowire 屬性(byName,byType,constructor),Spring IOC 容器可以自動為程式注入 bean;預設是 no,不啟用自動裝配;

<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-autowire="constructor"> <!-- 在此處設定 -->
  • byName:通過名稱進行自動匹配,根據類中宣告的屬性名稱選擇注入的值;
    // People.java
    private Dog dog1;
    <!-- beans.xml -->
    <bean id="dog1" class="com.java1234.entity.Dog">
            <property name="name" value="Tom"></property>
    </bean>
    
    <bean id="dog2" class="com.java1234.entity.Dog">
        <property name="name" value="Jack"></property>
    </bean>
        
    <bean id="people1" class="com.java1234.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="張三"></property>
        <property name="age" value="11"></property>
    </bean>    
    // 測試
    public void test1() {
        private ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
        People people=(People)ac.getBean("people1");
        System.out.println(people);
    }    

    結果是:取出的狗名叫:Tom, 注意看People.java裡面宣告的狗是 dog1.

    .

  • byType:根據型別進行自動匹配,class="com.java1234.entity.Dog 
  • constructor:和 byType 類似,只不過它是根據構造方法注入而言的,根據型別,自動注入;

建議:自動裝配機制慎用,它遮蔽了裝配細節,容易產生潛在的錯誤;

 

5.方法注入

Spring bean 作用域預設是 單例 singleton; 可以通過配置 prototype ,實現多例; 方法注入 lookup-method .

  1. 預設單例 :每次獲取的例項都是一樣的
    System.out.println(ac.getBean("dog")=ac.getBean("dog")); //返回true
  2. 配置多例:每次獲取的例項是不一樣的 ( scope="prototype" 
    <bean id="dog" class="com.java1234.entity.Dog" scope="prototype">
        <property name="name" value="Jack"></property>
    </bean>
    System.out.println(ac.getBean("dog")=ac.getBean("dog")); //返回false

    注:當把dog bean作為屬性注入給其他bean是,是同一條狗,而不是新的!所以可以使用lookup-method 方法注入修改

  3. bean注入時lookup-method
    <bean id="dog" class="com.java1234.entity.Dog" scope="prototype">
        <property name="name" value="Jack"></property>
    </bean>
        
    <bean id="people1" class="com.java1234.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="張三"></property>
        <property name="age" value="11"></property>
        <lookup-method name="getDog" bean="dog"/>  <!-- lookup-method -->
    </bean>

    注:此時要將getDog的方法改成抽象方法

    public abstract class People {
    
        private Dog dog;
        
        public abstract Dog getDog();
        
        public void setDog(Dog dog) {
            this.dog = dog;
        }   
    }

6.方法替換

假如,people1 有一條叫 Tom 的狗,people2 有一條叫 Jack 的狗,現在 people1 想要名叫 Jack 即 people2 的狗,即可用方法替換來實現。

此時需要將 people2 的 getDog() 方法替換成people1 的。

  • people2 實現介面 MethodReplacer
    public class People2 implements MethodReplacer {
    
        @Override
        public Object reimplement(Object arg0, Method arg1, Object[] arg2)
                throws Throwable {
            Dog dog=new Dog();
            dog.setName("Tom");
            return dog;
        }
    }
    <bean id="people2" class="com.java1234.entity.People2"></bean>
        
    <bean id="people1" class="com.java1234.entity.People">
        <property name="id" value="1"></property>
        <property name="name" value="張三"></property>
        <property name="age" value="11"></property>
        <replaced-method name="getDog" replacer="people2"></replaced-method>
        <!-- 用people2裡面的reimplement來替換people1裡面的getDog方法 -->
    </bean>

7.Bean之間的關係

  • 1. 繼承:抽象的Bean可以定義一些公共的屬性和方法( abstract="true"
    <!-- bstract="true" -->
    <bean id="abstractPeople" class="com.java1234.entity.People" abstract="true">
        <property name="className" value="高三5班"></property>
        <property name="age" value="19"></property>
    </bean>
        
    <!-- parent="abstractPeople" -->
    <bean id="lisi" parent="abstractPeople">  <!-- 無需class,可不建立實體類 -->
        <property name="id" value="2"></property>
        <property name="name" value="李四"></property>
        <property name="age" value="20"></property>  <!-- 屬性可重寫 -->
    </bean>
        
    <!-- 結果是:id=2——李四——高三5班——20歲 -->

     

  • 2. 依賴:未加入依賴的時候,按順序執行bean;加入依賴後,會先去執行依賴的 bean ( depends-on="autority" ),可用於許可權設定
    <!-- depends-on="autority" -->
    <bean id="zhangsan" parent="abstractPeople" depends-on="autority">
        <property name="id" value="1"></property>
        <property name="name" value="張三"></property>
    </bean>
    
    <bean id="autority" class="com.java1234.service.Authority"></bean>

     

  • 3. 引用:引用bean (ref),可參照前面的內容

8.Bean的作用範圍

  • 1. singleton:Spring ioc 容器中僅有一個 Bean 例項,Bean 以單例的方式存在;
  • 2. prototype:每次從容器中呼叫 Bean 時,都返回一個新的例項;
  • 3. request: 每次 HTTP 請求都會建立一個新的 Bean;
  • 4. session: 同一個 HTTP Session 共享一個 Bean;
  • 5. global session: 同一個全域性 Session 共享一個 Bean,一般用於 Portlet 應用環境;
  • 6. application: 同一個 Application 共享一個 Bean;
    <!-- scope="singleton/prototype/....." -->
    <bean id="dog" class="com.java1234.entity.Dog" scope="singleton">
        <property name="name" value="jack"></property>
    </bean>