Spring DI(依賴注入)之注解配置
1. 前言
上一節,我們通過 xml 文件的配置方式,實現了對多種依賴類型的注入,當然體會到了 xml 文件配置方式的弊端:有一點麻煩。
依賴注入是有兩種方式,一種是 xml ,另外一種就是注解的配置方式。
本節,我們演示下通過注解配置這種方式來實現注入依賴。
來吧 ,直入主題,莫浪費大好光陰…
2. 工程實例
2.1 注解的介紹
在正式使用注解之前,我們首先介紹下注解語法以及它的作用。
- @Autowired: 此注解自動按照類型注入。從容器中尋找符合依賴類型的實例,當使用該注解注入屬性時,set 方法可以省略。但是因為按照類型匹配,如果容器中有多個匹配的類型,會拋出異常,需要指定引入的實例 id。如果找不到匹配的實例,那么也會拋出異常;
- @Qualifier: 此注解不能單獨使用,它的作用是在按照類型注入的基礎之上,再按照 Bean 的 id 注入。所以如果是使用了 @Autowire 注解自動注入,但是容器中卻有多個匹配的實例,可以搭配此注解,指定需要注入的實例 id;
- @Resource 此注解的作用是指定依賴按照 id 注入,還是按照類型注入。當只使用注解,但是不指定注入方式的時候,默認按照 id 注入,找不到再按照類型注入。
2.2 @Autowired 注解
1. 為了測試效果,我們創建 Service 和 Dao 兩個類, Dao 作為 Service 的依賴。代碼如下:
//service實現類的代碼
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
public void saveUser() {
System.out.println("執行service中的保存邏輯");
}
}
//dao實現類的代碼
@Repository
public class UserDaoImpl implements UserDao {
public void saveUser() {
System.out.println("執行dao的保存方法");
}
}
代碼解釋:
上面代碼可以看到,兩個類的實例化方式都是通過注解注入到容器, 并且在 service 實現類中的 userDao 屬性上面加了注解 @Autowired
。
我們首先測試下:能否通過這個注解,實現依賴注入,另外再測試下它是否是按照類型注入。
2. 配置文件的內容為注解實現 IoC。
配置文件解釋: 注解實現 IoC 的章節說過,需要通過組件掃描來實例化容器。
3. 編寫測試代碼
public class SpringAnTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = context.getBean(UserService.class);
userService.saveUser();
}
}
測試結果:
結果解釋
可以看到 service 中的代碼執行,并且通過 dao 的示例調用的方法也執行了,那么說明 @Autowired
注解實現了屬性 userDao 的注入。
當然這種操作是小兒科,沒有一個同學覺得他有什么。 我們驗證下它的特點:set 方法我們是省略了,那么它是否按照類型注入的呢?
如果我們的實現類中有多個 userDao 接口的實現類呢,又該如何呢?
4. 添加 UserDaoImpl2 一樣實現 userDao 的接口,代碼如下:
@Repository
public class UserDaoImpl1 implements UserDao {
public void saveUser() {
System.out.println("執行dao1的保存方法");
}
}
測試結果
結果解釋:
可以看到上面控制臺打印的異常堆棧信息,清楚的提示錯誤原因,沒有指定的 bean 實例 UserDao 類型的,期待單個 bean 匹配,但是找到了兩個。
一個是 userDaoImpl
一個是 userDaoImpl1
??吹竭@可以證明: @Autowired
注解是按照類型注入,如果匹配的類型多了就會報錯。
疑問導出:
難道使用了 Spring 框架以后,我們的接口只能有一個實現類嗎? 當然不可能,畢竟我們看 Spring 的源碼的時候 已經看到了,很多的接口對應一大堆的實現類。
那么,針對這種多個接口實例的情況,怎么解決的呢?繼續我們注解的學習。
2.3 @Qualifier 注解
1. 此注解的作用,我們介紹過了,這里再看一下:它的作用是在按照類型注入的基礎之上,再按照 Bean 的 id 注入,不能單獨使用,搭配上面的 @Autiwired
注解。
在兩個實現類的基礎之上改造代碼如下:
@Service
public class UserServiceImpl implements UserService {
@Qualifier("userDaoImpl")
@Autowired
private UserDao userDao;
public void saveUser() {
System.out.println("執行service中的保存邏輯");
userDao.saveUser();
}
}
代碼解釋
在屬性注入的地方,通過注解 @Qualifier
的參數,指定了注入的 bean 實例 id 為 userDaoImpl。
2. 測試方法繼續執行查看結果。
結果解釋:
那么可以看到,我們的方法正常執行,而且執行的就是 userDaoImpl 中的方法。
3. 繼續改造 service 的代碼如下,將 @Qualifier
注解中的值換成 userDaoImpl1 以后再看看結果。
@Service
public class UserServiceImpl implements UserService {
@Qualifier("userDaoImpl1")
@Autowired
private UserDao userDao;
public void saveUser() {
System.out.println("執行service中的保存邏輯");
userDao.saveUser();
}
}
結果如下:
通過修改 @Qualifier
注解中 id 的屬性值 ,可以分別注入不同的實現類,那么證明了 @Qualifier
注解的作用。
2.4 @Resources 注解
此注解的作用是指定依賴按照 id 注入,還是按照類型注入。當只使用注解,但是不指定注入方式的時候,默認按照 id 注入,找不到時再按照類型注入。
語法如下:
@Resource //默認按照 id 為 userDao的bean實例注入
@Resource(name="userDao") //按照 id 為 userDao的bean實例注入
@Resource(type="UserDao") //按照 類型 為 UserDao的bean實例注入
這里就只做個語法的介紹,注解的使用大同小異,大家按照上方步驟自行測試即可。
3. 小結
本節重點講解注解注入依賴的使用,咱們做個總結:
1. 常用的注解有 3 種 :@Autowired
@Qualifier
@Resources
;
2. 注解注入的形式兩種 : 按照 bean 的 id 注入,或者按照 bean 的類型注入;
3. 哪種注解的目的,都是為了成功的注入使用的依賴,所以為了我們的開發服務,大家靈活使用即可。
不費力氣就能得到的… 只有年齡。