Spring經常使用的三種注入方式

Spring經過DI(依賴注入)實現IOC(控制反轉),經常使用的注入方式主要有三種:構造方法注入,setter注入,基於註解的注入。html

構造方法注入

先簡單看一下測試項目的結構,用maven構建的,四個包:
entity:存儲實體,裏面只有一個User類
dao:數據訪問,一個接口,兩個實現類
service:服務層,一個接口,一個實現類,實現類依賴於IUserDao
test:測試包 
這裏寫圖片描述 
在spring的配置文件中註冊UserService,將UserDaoJdbc經過constructor-arg標籤注入到UserService的某個有參數的構造方法java

<!-- 註冊userService --> <bean id="userService" class="com.lyu.spring.service.impl.UserService"> <constructor-arg ref="userDaoJdbc"></constructor-arg> </bean> <!-- 註冊jdbc實現的dao --> <bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>

若是隻有一個有參數的構造方法而且參數類型與注入的bean的類型匹配,那就會注入到該構造方法中。spring

public class UserService implements IUserService { private IUserDao userDao; public UserService(IUserDao userDao) { this.userDao = userDao; } public void loginUser() { userDao.loginUser(); } }
@Test public void testDI() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); // 獲取bean對象 UserService userService = ac.getBean(UserService.class, "userService"); // 模擬用戶登陸 userService.loginUser(); }

測試打印結果:jdbc-登陸成功

注:模擬用戶登陸的loginUser方法其實只是打印了一條輸出語句,jdbc實現的類輸出的是:jdbc-登陸成功,mybatis實現的類輸出的是:mybatis-登陸成功。 

問題一:若是有多個有參數的構造方法而且每一個構造方法的參數列表裏面都有要注入的屬性,那userDaoJdbc會注入到哪裏呢?mybatis

public class UserService implements IUserService { private IUserDao userDao; private User user; public UserService(IUserDao userDao) { System.out.println("這是有一個參數的構造方法"); this.userDao = userDao; } public UserService(IUserDao userDao, User user) { System.out.println("這是有兩個參數的構造方法"); this.userDao = userDao; this.user = user; } public void loginUser() { userDao.loginUser(); } }


結果:會注入到只有一個參數的構造方法中,而且通過測試注入哪個構造方法與構造方法的順序無關

這裏寫圖片描述app

問題二:若是隻有一個構造方法,可是有兩個參數,一個是待注入的參數,另外一個是其餘類型的參數,那麼此次注入能夠成功嗎?maven

public class UserService implements IUserService { private IUserDao userDao; private User user; public UserService(IUserDao userDao, User user) { this.userDao = userDao; this.user = user; } public void loginUser() { userDao.loginUser(); } }

結果:失敗了,即便在costract-arg標籤裏面經過name屬性指定要注入的參數名userDao也會失敗.

這裏寫圖片描述測試

問題三:若是咱們想向有多個參數的構造方法中注入值該在配置文件中怎麼寫呢?this

public class UserService implements IUserService { private IUserDao userDao; private User user; public UserService(IUserDao userDao, User user) { this.userDao = userDao; this.user = user; } public void loginUser() { userDao.loginUser(); } }

參考寫法:經過name屬性指定要注入的值,與構造方法參數列表參數的順序無關。spa

<!-- 註冊userService --> <bean id="userService" class="com.lyu.spring.service.impl.UserService"> <constructor-arg name="userDao" ref="userDaoJdbc"></constructor-arg> <constructor-arg name="user" ref="user"></constructor-arg> </bean> <!-- 註冊實體User類,用於測試 --> <bean id="user" class="com.lyu.spring.entity.User"></bean> <!-- 註冊jdbc實現的dao --> <bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>

問題四:若是有多個構造方法,每一個構造方法只有參數的順序不一樣,那經過構造方法注入多個參數會注入到哪個呢?hibernate

public class UserService implements IUserService { private IUserDao userDao; private User user; public UserService(IUserDao userDao, User user) { System.out.println("這是第二個構造方法"); this.userDao = userDao; this.user = user; } public UserService(User user, IUserDao userDao) { System.out.println("這是第一個構造方法"); this.userDao = userDao; this.user = user; } public void loginUser() { userDao.loginUser(); } }

結果:哪一個構造方法在前就注入哪個,這種狀況下就與構造方法順序有關。

這裏寫圖片描述

setter注入

配置文件以下:

<!-- 註冊userService --> <bean id="userService" class="com.lyu.spring.service.impl.UserService"> <!-- 寫法一 --> <!-- <property name="UserDao" ref="userDaoMyBatis"></property> --> <!-- 寫法二 --> <property name="userDao" ref="userDaoMyBatis"></property> </bean> <!-- 註冊mybatis實現的dao --> <bean id="userDaoMyBatis" class="com.lyu.spring.dao.impl.UserDaoMyBatis"></bean>

注:上面這兩種寫法均可以,spring會將name值的每一個單詞首字母轉換成大寫,而後再在前面拼接上」set」構成一個方法名,而後去對應的類中查找該方法,經過反射調用,實現注入。

切記:name屬性值與類中的成員變量名以及set方法的參數名都無關,只與對應的set方法名有關,下面的這種寫法是能夠運行成功的

public class UserService implements IUserService { private IUserDao userDao1; public void setUserDao(IUserDao userDao1) { this.userDao1 = userDao1; } public void loginUser() { userDao1.loginUser(); } }

還有一點須要注意:若是經過set方法注入屬性,那麼spring會經過默認的空參構造方法來實例化對象,因此若是在類中寫了一個帶有參數的構造方法,必定要把空參數的構造方法寫上,不然spring沒有辦法實例化對象,致使報錯。 
這裏寫圖片描述

基於註解的注入

在介紹註解注入的方式前,先簡單瞭解bean的一個屬性autowire,autowire主要有三個屬性值:constructor,byName,byType。

  • constructor:經過構造方法進行自動注入,spring會匹配與構造方法參數類型一致的bean進行注入,若是有一個多參數的構造方法,一個只有一個參數的構造方法,在容器中查找到多個匹配多參數構造方法的bean,那麼spring會優先將bean注入到多參數的構造方法中。

  • byName:被注入bean的id名必須與set方法後半截匹配,而且id名稱的第一個單詞首字母必須小寫,這一點與手動set注入有點不一樣。

  • byType:查找全部的set方法,將符合符合參數類型的bean注入。


下面進入正題:註解方式註冊bean,注入依賴 

主要有四種註解能夠註冊bean,每種註解能夠任意使用,只是語義上有所差別:

  1. @Component:能夠用於註冊全部bean
  2. @Repository:主要用於註冊dao層的bean
  3. @Controller:主要用於註冊控制層的bean
  4. @Service:主要用於註冊服務層的bean

描述依賴關係主要有兩種:

  • @Resource:java的註解,默認以byName的方式去匹配與屬性名相同的bean的id,若是沒有找到就會以byType的方式查找,若是byType查找到多個的話,使用@Qualifier註解(spring註解)指定某個具體名稱的bean。
@Resource @Qualifier("userDaoMyBatis") private IUserDao userDao; public UserService(){
  • @Autowired:spring註解,默認是以byType的方式去匹配與屬性名相同的bean的id,若是沒有找到,就經過byName的方式去查找,
@Autowired @Qualifier("userDaoJdbc") private IUserDao userDao;

寫在最後:雖然有這麼多的注入方式,可是實際上開發的時候本身編寫的類通常用註解的方式註冊類,用@Autowired描述依賴進行注入,通常實現類也只有一種(jdbc or hibernate or mybatis),除非項目有大的變更,因此@Qualifier標籤用的也較少;可是在使用其餘組件的API的時候用的是經過xml配置文件來註冊類,描述依賴,由於你不能去改人家源碼嘛。

 

轉載:http://www.javashuo.com/article/p-elnfbuvh-hg.html

相關文章
相關標籤/搜索