Spring-- IOC容器詳解

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

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

       通俗點說就是不創建對象。以前我們要調用一個對象的方法,首先要new一個對象。但使用IOC容器,在代碼中不直接與對象連接,而是在配置文件中描述要使用哪一個對象。容器負責將這些聯繫在一起。

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

採用set方法注入,給屬性添加一個set方法,並對其進行賦值

publicclass UserManagerImplimplements UserManager {

    private UserDaouserDao;

    publicvoid setUserDao(UserDao userDao) {

        this.userDao = userDao;

    }

}

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

publicclass UserManagerImplimplements UserManager {

    private UserDaouserDao;

    public UserManagerImpl(UserDao userDao) {

        this.userDao = userDao;

    }

}

配置文件:

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

     <propertyname="userDao"ref="usrDao4Oracle"/>

  </bean>

配置文件:

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

    <constructor-argref="userDao4Mysql"/>

</bean>

set注入特點:

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

        對於複雜的依賴關係,如果採用構造注入,會導致構造器過於臃腫,難以閱讀。Spring在創建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="2009年12月14日" />
	</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="yyyy年MM月dd日"/>
					</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>


         bean3,bean4中有相同的屬性,id,name,sex,則可以將其抽象出一個抽象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容器中有這種配置嗎?當然有,那就是bean的scope作用域。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控制反轉,大量減少了Factory和Singleton的數量,使代碼層次更加清晰。Spring的IOC容器是一個輕量級的容器,沒有侵入性,不需要依賴容器的API,也不需要實現一些特殊接口。而一個合理的設計最好儘量避免侵入性。減少了代碼中的耦合,將耦合推遲到了配置文件中,發生了變化也更容易控制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章