本文轉載自:https://blog.csdn.net/u012260238/article/details/81110136
一、@Qualifier
一般情況下:在Controller中需要注入service,一般用@Reource( 默認按名稱裝配,當找不到與名稱匹配的bean才會按類型裝配) 和
@Autowired(默認按類型裝配,如果我們想使用按名稱裝配,可以結合@Qualifier注解一起使用)
一般情況下使用@@Autowired時:
那么這個service有兩個實現類如何區分開這兩個impl呢?
請看下面的例子:
接口:
1 public interface EmployeeService { 2 public EmployeeDto getEmployeeById(Long id); 3 }
接口對應的兩個實現類:EmployeeServiceImpl和EmployeeServiceImpl1:接口對應的兩個實現類:EmployeeServiceImpl和EmployeeServiceImpl1:
1 @Service("employeeService") 2 public class EmployeeServiceImpl implements EmployeeService { 3 public EmployeeDto getEmployeeById(Long id) { 4 return new EmployeeDto(); 5 } 6 }
1 @Service("employeeService1") 2 public class EmployeeServiceImpl1 implements EmployeeService { 3 public EmployeeDto getEmployeeById(Long id) { 4 return new EmployeeDto(); 5 } 6 }
調用代碼如下:
1 @Controller 2 @RequestMapping("/emplayee.do") 3 public class EmployeeInfoControl { 4 @Autowired 5 EmployeeService employeeService; 6 7 @RequestMapping(params = "method=showEmplayeeInfo") 8 public void showEmplayeeInfo(HttpServletRequest request, HttpServletResponse response, EmployeeDto dto) { 9 #略 10 } 11 }
在啟動tomcat時報如下錯誤:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'employeeInfoControl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.test.service.EmployeeService com.test.controller.EmployeeInfoControl.employeeService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.test.service.EmployeeService] is defined: expected single matching bean but found 2: [service1, service2]
--》 其實報錯信息已經說得很明確了,在@Autowired時,由於有兩個類實現了EmployeeService接口,所以Spring不知道應該綁定哪個實現類,所以拋出了如上錯誤。
這個時候就要用到@Qualifier注解了,qualifier的意思是合格者,通過這個標示,表明了哪個實現類才是我們所需要的,我們修改調用代碼,添加@Qualifier注解,需要注意的是@Qualifier的參數名稱必須為我們之前定義@Service注解的名稱之一!
1 @Controller 2 @RequestMapping("/emplayee.do") 3 public class EmployeeInfoControl { 4 5 @Autowired 6 @Qualifier("employeeService") 7 EmployeeService employeeService; 8 9 @RequestMapping(params = "method=showEmplayeeInfo") 10 public void showEmplayeeInfo(HttpServletRequest request, HttpServletResponse response, EmployeeDto dto) { 11 #略 12 } 13 }
二、@Primary:和@Qualifier 一樣,@Primary也一樣,使用場景經常是:在spring 中使用注解,常使用@Autowired, 默認是根據類型Type來自動注入的。但有些特殊情況,對同一個接口,可能會有幾種不同的實現類,而默認只會采取其中一種的情況下 @Primary 的作用就出來了。
簡單例子:
接口:
1 public interface Singer { 2 String sing(String lyrics); 3 }
有下面的兩個實現類:
1 @Component // 加注解,讓spring識別 2 public class MetalSinger implements Singer{ 3 4 @Override 5 public String sing(String lyrics) { 6 return "I am singing with DIO voice: "+lyrics; 7 } 8 }
1 //注意,這里沒有注解 2 public class OperaSinger implements Singer { 3 @Override 4 public String sing(String lyrics) { 5 return "I am singing in Bocelli voice: "+lyrics; 6 } 7 }
下面就是注入上面的接口實現類:
1 @Component 2 public class SingerService { 3 private static final Logger logger = LoggerFactory.getLogger(SingerService.class); 4 5 @Autowired 6 private Singer singer; 7 8 public String sing(){ 9 return singer.sing("song lyrics"); 10 } 11 }
結果:I am singing with DIO voice: song lyrics.
原因很簡單,就是 OperaSinger 這個類上面根本沒有加上注解@Copmonent 或者 @Service, 所以spring 注入的時候,只能找到 MetalSinger 這個實現類. 所以才有這個結果。
但是如果一旦 OperaSinger 這個類加上了@Copmonent 或者 @Service 注解,有趣的事情就會發生,你會發現一個錯誤的結果或異常:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [main.service.Singer] is defined: expected single matching bean but found 2: metalSinger,operaSinger
提示很
1 @Primary 2 @Component 3 public class OperaSinger implements Singer{ 4 5 @Override 6 public String sing(String lyrics) { 7 return "I am singing in Bocelli voice: "+lyrics; 8 } 9 }
如果代碼改成這樣,再次運行,結果如下:
“I am singing in Bocelli voice: song lyrics”, 用@Primary 告訴spring 在猶豫的時候優先選擇哪一個具體的實現。
明確了,spring 根據類型無法選擇到底注入哪一個。這個時候@Primay 可以閃亮登場了。
三、擴展:Spring注解常用匯總
使用注解之前要開啟自動掃描功能
其中base-package為需要掃描的包(含子包)
@Configuration把一個類作為一個IoC容器,它的某個方法頭上如果注冊了@Bean,就會作為這個Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延遲初始化
@Service用於標注業務層組件、
@Controller用於標注控制層組件(如struts中的action)
@Repository用於標注數據訪問組件,即DAO組件。
@Component泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。
@Scope用於指定scope作用域的(用在類上)
@PostConstruct用於指定初始化方法(用在方法上)
@PreDestory用於指定銷毀方法(用在方法上)
@Resource 默認按名稱裝配,當找不到與名稱匹配的bean才會按類型裝配。
@DependsOn:定義Bean初始化及銷毀時的順序
@Primary:自動裝配時當出現多個Bean候選者時,被注解為@Primary的Bean將作為首選者,否則將拋出異常
@Autowired 默認按類型裝配,如果我們想使用按名稱裝配,可以結合@Qualifier注解一起使用
@Autowired @Qualifier("personDaoBean") 存在多個實例配合使用