1. 程式人生 > >Spring整理系列(02)——spring依賴注入,組裝物件之間的依賴關係

Spring整理系列(02)——spring依賴注入,組裝物件之間的依賴關係

上篇文章整理了spring容器註冊bean的實現方式,本文將整理spring注入bean的實現方式,多數文章按照setter和構造器注入的緯度來介紹,本文將按照如何採用setter和構造器的緯度來整理,即xml配置注入、xml配置自動裝配、註解自動裝配三種方式,希望說的不囉嗦。

一、xml配置注入,手動裝配,提供setter方法或者constructor建構函式

1、需提供setter方法方式:

spring的xml配置檔案:

    <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl"
>
</bean> <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl"> <!-- 配置注入屬性 --> <property name="userDao" ref="userDao"></property> </bean>

UserServiceImpl:

    //宣告UserDao屬性,名字與xml中property的name名稱不具有關聯性,比如可以叫userDaoAlias
private UserDao userDao; //setter方法,其中setXxxx的Xxxx要與xml檔案中property標籤中name屬性值一致,首字母大寫,具有關聯性 public void setUserDao(UserDao userDao) { System.out.println("setUserDao注入"); this.userDao = userDao; }

2、需提供構造器方式:

spring的xml配置檔案:

    <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl"
>
</bean> <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl"> <!-- 配置注入屬性 --> <constructor-arg name="userDao" ref="userDao"></constructor-arg> </bean>

UserServiceImpl:

    //宣告UserDao屬性,屬性名與<constructor-arg>標籤中name屬性值無關
    private UserDao userDao;

    //引數名與<constructor-arg>標籤中name屬性值具有關聯性
    public UserServiceImpl(UserDao userDao){
        System.out.println("構造器UserServiceImpl注入");
        this.userDao = userDao;
    }

二、xml配置注入,自動裝配,提供setter方法或者constructor建構函式

spring提供了三種自動裝配的方式,實現的方式為在bean標籤中新增autowire屬性或者在beans中新增全域性的default-autowire屬性,屬性值如下:

1、byName:把Bean的屬性具有相同名字的的其他Bean自動裝配到Bean的對應屬性中

spring的xml配置檔案:

    <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl"></bean>

    <!-- 註冊bean並自動裝配所有屬性bean -->
    <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl" autowire="byName"></bean>

UserServiceImpl:
與前面的1、需提供setter方法方式相同,需要setter方法

    //宣告UserDao屬性不具有關聯性
    private UserDao userDao;

    //setter方法,其中setXxxx的Xxxx要與xml檔案中property標籤中name屬性值一致,首字母大寫,具有關聯性
    public void setUserDao(UserDao userDao) {
        System.out.println("自動裝配byName-setUserDao注入");
        this.userDao = userDao;
    }

2、byType:把與Bean的屬性具有相同型別的的其他Bean 自動裝配Bean的對應屬性當中,如果存在多個該型別bean,那麼丟擲異常,並指出不能使用byType進行自動裝配;如果沒有找到相匹配的bean,則什麼事都不發生

spring的xml配置檔案:

    <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl"></bean>

    <!-- 註冊bean並自動裝配所有屬性bean -->
    <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl" autowire="byType"></bean>

UserServiceImpl:

byType方式同樣依賴於setter方法,但與setter方法名不再具有關聯性,而是與setter的引數型別具有關聯性,setter引數型別必須是所注入bean的型別或父型別

    //宣告UserDao屬性名不具有關聯性
    private UserDao userDao;

    //setter方法的引數型別必須是所注入bean的型別或父型別
    public void setUserDao(UserDao userDao) {
        System.out.println("自動裝配byType-setUserDao注入");
        this.userDao = userDao;
    }


注意:在應用上下文(spring容器)中,如果有多個bean的型別與該bean的自動裝配屬性相匹配,那麼就會出錯,因為byType方式只允許匹配一個型別相同的Bean。


spring提供了兩種選擇,可以設定一個首選bean,或者排除一些bean。

2.1)、設定首選bean:
<bean>元素的primary屬性代表是否是首選bean,如果標註為true,那麼該bean將成為首選bean,但是spring預設每個bean的primary屬性都是true,所以如果需要設定首選bean需要將那些非首選bean的primary屬性標註為false。

spring的xml配置檔案:

    <!-- 將UserDaoImpl註冊為非首選bean -->
    <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl" primary="false"></bean>

    <!-- 將UserDaoImpl2註冊為首選bean -->
    <bean id="userDao2" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl2" primary="true"></bean>

    <!-- 設定自動裝配方式為byType -->
    <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl" autowire="byType"></bean>

UserServiceImpl:程式碼不變,UserDaoImpl2的例項save方法被執行。

2.2)、排除一些bean:
在自動裝配的過程當中,想排除某些bean的時候,可是使用把autowire-candidate屬性設定為false。

spring的xml配置檔案:

    <!-- 註冊bean -->
    <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl"></bean>

    <!-- 註冊bean,但是將該bean作為屬性時被自動裝配設定為false,因此該bean作為屬性不會被自動裝配 -->
    <bean id="userDao2" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl2" autowire-candidate="false"></bean>

    <!-- 設定自動裝配方式為byType -->
    <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl" autowire="byType"></bean>

UserServiceImpl:程式碼不變,UserDaoImpl的例項save方法被執行。



3、constructor:把與Bean的構造器入參具有相同型別的其他Bean自動裝配到構造器的對應入參中,如果容器中沒有找到與構造器引數型別一致的bean,那麼丟擲異常

spring的xml配置檔案:

    <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl"></bean>

    <!-- 註冊bean並自動裝配所有屬性bean -->
    <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl" autowire="constructor"></bean>



UserServiceImpl:

    private UserDao userDao;

    //constructor自動裝配依賴於構造器引數型別,與名稱無關,型別必須是所注入bean的型別或父型別
    public UserServiceImpl(UserDao userDao){
        System.out.println("自動裝配構造器UserServiceImpl注入");
        this.userDao = userDao;
    }




4、補充:設定全域性的預設自動裝配

如果在一個配置檔案中,所有的裝配都使用同一種自動配置方式的話, 要在每個bean宣告的時候都加上一個autowire屬性比較麻煩,為了避免這樣的重複操作,可以使用預設自動裝配。

使用預設自動裝配的方法是在元素中新增一個default-autowire屬性,但如果bean上直接設定autowire屬性會覆蓋掉預設自動裝配的配置。

default-autowire屬性值與上面單獨bean設定autowire屬性值一樣,都是三個,byName、byType、constructor。

spring的xml配置檔案:

<beans ...
  default-autowire="byName">
</beans>

UserServiceImpl:參照上面單獨配置bean的形式

三、註解自動裝配,可以不用提供setter方法或者constructor建構函式

在使用註解裝配之前,首先要開啟註解裝配的方式,那就是在配置檔案中加上下面這句話<context:annotation-config></context:annotation-config>,也可以使用<context:component-scan>標籤(兩者的區別在Spring整理系列(01)——spring概念簡介、bean掃描與註冊實現方式中有提到)標籤。

使用@Autowired註解,可以用在屬性、setter方法、constructor構造方法上,實現自動裝配。

spring的xml配置檔案:

    <!-- 開啟註解配置 -->
    <context:annotation-config></context:annotation-config>

    <!-- 註冊bean -->
    <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl"></bean>

    <!-- 註冊bean -->
    <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl"></bean>

UserServiceImpl:

1、註解在setter方法上:

    private UserDao userDao;

    //添加註解,匹配注入與引數型別有關,與引數名稱、setter方法名稱、成員變數屬性名稱無關
    @Autowired
    public void setUserDao(UserDao userDao) {
        System.out.println("註解自動裝配setUserDao注入");
        this.userDao = userDao;
    }

2、constructor構造方法上:

    private UserDao userDao;

    //添加註解,匹配注入與引數型別有關,與引數名稱、成員變數屬性名稱無關
    @Autowired
    public UserServiceImpl(UserDao userDao){
        System.out.println("註解自動裝配構造器UserServiceImpl注入");
        this.userDao = userDao;
    }

3、宣告的屬性上:

    //添加註解,先按照屬性名稱匹配注入,如果未找到則按照屬性型別匹配注入
    @Autowired
    private UserDao userDao;
    @Value("我就是注入strValue屬性的值")
    private String strValue;

使用表示式來動態的計算並裝配屬性的值,比如使用spel表示式從系統屬性中取得一個值

@Value("#{systemProperties.myFavoriteSong}")
private String strValue;

也可以像使用EL表示式一樣,獲取spring上下文中載入的*.properties資原始檔資料:

@Value("${jdbc.url}")
private String url;