Spring之---@Primary 和 @Qualifier

本文转载自: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") 存在多个实例配合使用

原文地址:https://www.cnblogs.com/whhjava/p/10599799.html