1. 程式人生 > >Spring-IOC容器詳解

Spring-IOC容器詳解

(最近在看spring,看到黑馬視訊教程裡面有些東西寫的還不錯,就稍微整合了一些,跟大家分享一下!    )

Spring作為一個在java界廣泛使用且評價頗高的一個開源框架,給我們提供了好多的功能,極大的方便了我們的開發。此處介紹IOC容器和AOP概念。

    IOCInversion of Control)控制反轉:本來是由應用程式管理的物件之間的依賴關係,現在交給了容器管理,這就叫控制反轉,即交給了IOC容器,SpringIOC容器主要使用DI方式實現的。不需要主動查詢,物件的查詢、定位和建立全部由容器管理。

    通俗點說就是不建立物件。以前我們要呼叫一個物件的方法,首先要new一個物件。但使用

IOC容器,在程式碼中不直接與物件連線,而是在配置檔案中描述要使用哪一個物件。容器負責將這些聯絡在一起。

    IOC容器的物件例項化是通過配置檔案來實現的。術語上這叫做注入。注入有兩種形式,採用構造方法注入和採用setter注入。具體的注入形式如下

1.採用set方法注入

給屬性新增一個set方法,並對其進行賦值

publicclass UserManagerImplimplements UserManager {

    private UserDaouserDao;

    publicvoid setUserDao(UserDao userDao) {

        this.userDao = userDao;

    }

}

配置檔案:

<beanid="userManager"class="com.bjpowernode.spring.manager.UserManagerImpl">

     <property name="userDao" ref="usrDao4Oracle"/>

  </bean>

set注入特點:

    與傳統的JavaBean的寫法更相似,程式設計師更容易理解、接受,通過setter方式設定依賴關係顯得更加直觀、明顯;

    對於複雜的依賴關係,如果採用構造注入,會導致構造器過於臃腫,難以閱讀。Spring在建立Bean例項時,需要同時例項化其依賴的全部例項,因而導致死你功能下降。而使用設定注入,則避免這下問題;

    尤其在某些屬性可選的情況下,多引數的構造器更加笨拙。

2.採用構造方法注入,在構造方法中對屬性進行賦值

publicclass UserManagerImplimplements UserManager {

    private UserDaouserDao;

    public UserManagerImpl(UserDao userDao) {

        this.userDao = userDao;

    }

}

配置檔案:

<beanid="userManager"class="com.bjpowernode.spring.manager.UserManagerImpl">

    <constructor-arg ref="userDao4Mysql"/>

</bean>

構造方法注入特點:

    構造注入可以在構造器中決定依賴關係的注入順序,優先依賴的優先注入。

<p LINE-HEIGHT= 25px" align="left">       對於依賴關係無須變化的Bean,構造注入更有用處;因為沒有setter方法,所有的依賴關係全部在構造器內設定,因此,不用擔心後續程式碼對依賴關係的破壞。

    依賴關係只能在構造器中設定,則只有元件的建立者才能改變元件的依賴關係。對元件的呼叫者而言,元件內部的依賴關係完全透明,更符合高內聚的原則;

    建議採用以設定注入為主,構造注入為輔的注入策略。對於依賴關係無須變化的注入,儘量採用構造注入;而其他的依賴關係的注入,則考慮採用設定注入。

此處我們說的普通屬性的注入,但是還有一些列表,陣列,map等型別的變數。

我們看一下他們的注入形式:

    <bean id="bean1" class="com.bjpowernode.spring.Bean1">  

            <property name="strValue" value="Hello_Spring"/>  

<!--  

            <property name="intValue" value="123"/>

             -->  

            <property name="intValue">  

                <value>123</value>  

            </property>  

            <property name="listValue">  

                <list>  

                    <value>list1</value>  

                    <value>list2</value>  

                </list>  

            </property>  

            <property name="setValue">  

                <set>  

                    <value>set1</value>  

                    <value>set2</value>  

                </set>  

            </property>  

            <property name="arrayValue">  

                <list>  

                    <value>array1</value>  

                    <value>array2</value>  

                </list>  

            </property>  

            <property name="mapValue">  

                <map>  

                    <entry key="k1" value="v1"/>  

                    <entry key="k2" value="v2"/>  

                </map>  

            </property>  

            <property name="dateValue" value="20091214" />  

        </bean>  

       spring中並不是所有型別的編輯器都實現好了,有些型別比如時間他就沒有實現。需要我們自己去定義。如何自定義屬性編輯器呢?首先,要繼承 PropertyEditorSupport類,然後覆蓋setAsText()方法,最後將自定義的屬性編輯器注入到spring

public class UtilDatePropertyEditorextends PropertyEditorSupport {

    private Stringpattern;

    @Override

    publicvoid setAsText(String text)throws IllegalArgumentException {

        System.out.println("---UtilDatePropertyEditor.setAsText()--->" + text);

        try {

            Date date = new SimpleDateFormat(pattern).parse(text);

            this.setValue(date);

        } catch (ParseException e) {

            e.printStackTrace();

            thrownew IllegalArgumentException(text);

        }

    }

    publicvoid setPattern(String pattern) {

        this.pattern = pattern;

    }   

}

       這裡pattern匹配形式,我們採用的是set注入。配置檔案中實現為:

<bean id="customEditors" class="org.springframework.beans.factory.config.CustomEditorConfigurer">

<property name="customEditors">

<map>

<entry key="java.util.Date">

<bean class="com.bjpowernode.spring.UtilDatePropertyEditor">

<property name="pattern" value="yyyyMMdd"/>

</bean>

</entry>

</map>

</property>

</bean>

      從上面可以看出,配置檔案中每一個類用bean標籤來標識,屬性用property來標識。如果屬性多的話,配置檔案也會很繁雜。有沒有某種情況能夠減少配置檔案的一些設定呢?確實是可以的,如果幾個bean都有相同的屬性,那這些屬性是可以抽象出來的。比如:

<bean id="AbstractBean"abstract="true">

        <propertyname="id"value="100"/>

        <propertyname="name"value="zhangsan"/>

        <propertyname="sex"value="nan"/>

</bean>    

<beanid="bean3"class="com.bjpowernode.spring.Bean3"parent="AbstractBean"/>

<beanid="bean4"class="com.bjpowernode.spring.Bean4"parent="AbstractBean">

     <propertyname="age">

          <value>90</value>

     </property>

</bean>

         bean3bean4中有相同的屬性,idnamesex,則可以將其抽象出一個抽象bean,然後,在具體bean中指定其parent標籤為抽象bean

        我們都知道正則表示式,用一個統一的格式表示多種不同的字元。在IOC中也有類似的功能。有得時候某個物件中包含其他物件的屬性。如果,這些屬性名稱 name間或者型別(具體的包名類名)有某種關係的話,是可以不用顯示呼叫的。IOC容器自動就回去查詢。如:

    <beans ...  

               default-autowire="byName"  

               >  

        <!--   

        <bean id="bean2" class="com.bjpowernode.spring.Bean2">  

            <property name="bean3" ref="bean3"/>    

            <property name="bean4">  

                <ref bean="bean4"/>  

            </property>  

            <property name="bean5" ref="bean5"/>  

        </bean>  

        -->  

        <bean id="bean2" class="com.bjpowernode.spring.Bean2"/>  

    <beans ...  

               default-autowire="byType"  

               >  

        <!--   

        <bean id="bean2" class="com.bjpowernode.spring.Bean2">  

            <property name="bean3" ref="bean3"/>    

            <property name="bean4">  

                <ref bean="bean4"/>  

            </property>  

            <property name="bean5" ref="bean5"/>  

        </bean>  

        -->  

        <bean id="bean2" class="com.bjpowernode.spring.Bean2"/>  

        <bean id="bean322" class="com.bjpowernode.spring.Bean3">  

            <property name="id" value="100"/>  

            <property name="name" value="zhangsan"/>  

            <property name="sex" value="nan"/>  

        </bean>  

        IOC容器實現的bean配置與我們在程式碼中new例項達到的效果是一樣的。那我們例項化的時候,可以採用單例模式,只保證有一個例項在執行,也可以多個例項執行。IOC容器中有這種配置嗎?當然有,那就是beanscope作用域。singleton預設值,每次呼叫getBean()IOC容器中取得的物件是相同的。即單例。而prototype,則是每次呼叫getBean()IOC容器中取得物件是不相同的。即相當於普通的例項化。

 <bean id="bean1"class="com.bjpowernode.spring.Bean1"scope="prototype"/>

或者

<bean id="bean1"class="com.bjpowernode.spring.Bean1"scope="singleton"/>

         通過IOC控制反轉,大量減少了FactorySingleton的數量,使程式碼層次更加清晰。SpringIOC容器是個輕量級的容器,沒有侵入性,不需要依賴容器的API,也不需要實現一些特殊介面。而一個合理的設計最好儘量避免侵入性。減少了程式碼中的耦合,將耦合推遲到了配置檔案中,發生了變化也更容易控制。

AOPaspect object programming)就是面向切面程式設計

AOP功能就是讓關注點程式碼與業務程式碼分離!

瞭解AOP需要清楚一些概念:

關注點

重複程式碼就叫做關注點;

切面

 關注點形成的類,就叫切面()

 面向切面程式設計,就是指 對很多功能都有的重複的程式碼抽取,再在執行的時候業務方法上動態植入“切面類程式碼”。

切入點

執行目標物件方法,動態植入切面程式碼。

可以通過切入點表示式,指定攔截哪些類的哪些方法; 給指定的類在執行的時候植入切面類程式碼。

切入點表示式:

可以對指定的“方法”進行攔截,從而給指定的方法所在的類生層代理物件。