Spring的@Autowired加到接口上但獲取的是實現類的問題
@Autowired加到接口上但獲取的是實現類
問題
Spring的@Autowired加到接口上但獲取的是實現類?
/* 類 @Controller註解,會在spring容器中實例化對象 */ @Controller public class UserContoller{ @Autowired // 先按類型找,然後按id為屬性名去找 private UserService userService; //為什麼他會拿到userServiceImpl? // @Autowired會幫你按UserService的類型去容器中找唯一bean對象 // 1、容器沒有該類型的對象:報錯 // 2、容器中有該類型的唯一bean對象,就將該唯一bean對象賦值給該屬性 ///3、容器中有多個【兩個及以上】該類型的唯一bean對象, // 它會再根據該屬性名去容器中找, // 看看容器中的哪個bean對象的id值和該屬性名一致, // 如果有,就將容器中該對象賦值給該屬性,如果沒有報錯。 } /* 接口 */ public interface UserService{} /* 類 @Service註解,會在spring容器中實例化對象 */ @Service public class UserServiceImpl implements UserService{}
為什麼他會拿到userServiceImpl?
@Autowired先按類型找,然後再按id為屬性名去找
他會幫你按UserService的類型去容器中找唯一bean對象
- 1.容器沒有該類型的對象:報錯
- 2.容器中有該類型的唯一bean對象,就將該唯一bean對象賦值給該屬性
- 3.容器中有多個【兩個及以上】該類型的唯一bean對象,
它會再根據該屬性名去容器中找,看看容器中的哪個bean對象的id值和該屬性名一致,如果有,就將容器中該對象賦值給該屬性,如果沒有報錯。
然後通過多態的向上轉型就賦值成功。等價於之前手動賦值
UserService userService = new UserServiceImpl();
@Autowired一個接口有多個實現類
@Autowired是spring的註解,默認使用的是byType的方式向Bean裡面註入相應的Bean。
例如
@Autowired private UserService userService;
這段代碼會在初始化的時候,在spring容器中尋找一個類型為UserService的bean實體註入,關聯到userService的引入上。
但是如果UserService這個接口存在多個實現類的時候,就會在spring註入的時候報錯,具體如下:
public class UserService1 implements UserService public class UserService2 implements UserService
當存多個UserService的實現類時,錯誤信息如下:
2016-08-05 14:53:53,795 ERROR [org.springframework.test.context.TestContextManager] – <Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@14a2f921] to prepare test instance [UserServiceTest@3c87521]>
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'UserServiceTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private yjc.demo.service.UserService UserServiceTest.userService; nested exception is he[yjc.demo.service.UserService] is defined: expected single matching bean but found 2: userService1,userService2
拋出瞭org.springframework.beans.factory.BeanCreationException,而原因是註入的時候發現有2個匹配的bean,但是不知道要註入哪一個:expected single matching bean but found 2: userService1,userService2
那麼如何應對多個實現類的場景呢,看一下代碼:
@Autowired private UserService userService1; @Autowired private UserService userService2; @Autowired @Qualifier(value = "userService2") private UserService userService3; @Test public void test(){ System.out.println(userService1.getClass().toString()); System.out.println(userService2.getClass().toString()); System.out.println(userService3.getClass().toString()); }
運行結果:
class yjc.demo.serviceImpl.UserService1
class yjc.demo.serviceImpl.UserService2
class yjc.demo.serviceImpl.UserService2
運行結果成功,說明瞭2種處理多個實現類的方法:
1.變量名用userService1,userService2,而不是userService。
通常情況下@Autowired是通過byType的方法註入的,可是在多個實現類的時候,byType的方式不再是唯一,而需要通過byName的方式來註入,而這個name默認就是根據變量名來的。
2.通過@Qualifier註解來指明使用哪一個實現類,實際上也是通過byName的方式實現。
由此看來,@Autowired註解到底使用byType還是byName,其實是存在一定策略的,也就是有優先級。優先用byType,而後是byName。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 深入分析@Resource和@Autowired註解區別
- 一文搞懂Spring中@Autowired和@Resource的區別
- Spring Bean自動裝配入門到精通
- Spring框架基於xml實現自動裝配流程詳解
- 一篇文章教帶你瞭解Java Spring之自動裝配