天天看點

Springs 依賴注入,組裝對象之間的依賴關系(2)

整理了spring容器注冊bean的實作方式,本文将整理spring注入bean的實作方式,多數文章按照setter和構造器注入的緯度來介紹,本文将按照如何采用setter和構造器的緯度來整理,即xml配置注入、xml配置自動裝配、注解自動裝配三種方式。

xml配置注入,手動裝配,提供setter方法或者constructor構造函數

需提供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;
    }
           

需提供構造器方式

<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屬性,屬性名與标簽中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屬性,屬性值如下:

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

<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>           

與前面的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;
    }           

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

<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>           

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:

元素的primary屬性代表是否是首選bean,如果标注為true,那麼該bean将成為首選bean,但是spring預設每個bean的primary屬性都是true,是以如果需要設定首選bean需要将那些非首選bean的primary屬性标注為false。

<!-- 将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。

<!-- 注冊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,那麼抛出異常

<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>           

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。

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

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

注解自動裝配,可以不用提供setter方法或者constructor構造函數

在使用注解裝配之前,首先要開啟注解裝配的方式,那就是在配置檔案中加上下面這句話,也可以使用标簽。

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

<!-- 開啟注解配置 -->
    <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>           

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;
           

4、補充:@Value注解基本類型資料或動态裝配資料

@Value("我就是注入strValue屬性的值")
private String strValue;
           

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

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

也可以像使用EL表達式一樣,擷取spring上下文中加載的*.properties資源檔案資料:

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

作者:glowd

原文:

https://blog.csdn.net/zengqiang1/article/details/54601044

版權聲明:本文為部落客原創文章,轉載請附上博文連結!