首頁 > 軟體

Spring的@Autowired加到介面上但獲取的是實現類的問題

2022-10-04 14:00:22

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

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com