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;