学习蚂蚁课堂关于Spring源码的课程:@Qualifier和@Primary的区别
假设一个接口下有两个实现类,这时候使用@Autowired获取的时候会有什么问题?怎么解决?
* UserService
* UserService001Impl
* UserService002Impl
*
* @Autowired
* UserService
*
* @Autowired默认的情况下使用 类型查找
会报错:
No qualifying bean of type ‘com.jiyu.v4.service.UserService’ available: expected single matching bean but found 2: userService001Impl,userService002Impl
代码:
(1)配置类:
package com.jiyu.v4.config;
import com.jiyu.v4.ServiceImpl.OrderServiceImpl;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* 别忘了扫包,不然无法注入bean
*/
@ComponentScan("com.jiyu.v4")
@Configuration
public class MyConfig {
}
(2)UserService接口
package com.jiyu.v4.service;
/**
* @author jiyu
* @date 2020/11/07 10:12
*
* 假设一个接口下有两个实现类,这时候使用@Autowired获取的时候
* UserService
* UserService001Impl
* UserService002Impl
*
* @Autowired
* UserService
*
* 因为@Autowired默认的情况下使用 类型查找
* SpringBoot 多数据源 设置默认的时候(优先级)
*/
public interface UserService {
void add();
}
(3)
package com.jiyu.v4.ServiceImpl;
import com.jiyu.v4.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author jiyu
* @date 2020/11/07 10:23
*/
@Component
public class OrderServiceImpl {
@Autowired
// @Qualifier("userService001Impl")
// @Resource(name = "userService001Impl")
private UserService userService;
public void add(){
System.out.println("11");
userService.add();
}
}
(4)
package com.jiyu.v4.ServiceImpl;
import com.jiyu.v4.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* @author jiyu
* @date 2020/11/07 10:14
*/
@Service
@Primary
public class UserService001Impl implements UserService {
public void add() {
System.out.println("UserService001Impl");
}
}
(5)
package com.jiyu.v4.ServiceImpl;
import com.jiyu.v4.service.UserService;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* @author jiyu
* @date 2020/11/07 10:14
*/
@Service
public class UserService002Impl implements UserService {
public void add() {
System.out.println("UserService002Impl");
}
}
(6)
package com.jiyu.v4;
import com.jiyu.v4.config.MyConfig;
import com.jiyu.v4.ServiceImpl.OrderServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author jiyu
* @date 2020/11/07 10:46
*/
public class V4Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
OrderServiceImpl orderServiceImpl = (OrderServiceImpl) annotationConfigApplicationContext.getBean("orderServiceImpl");
orderServiceImpl.add();
}
}
解决办法是:
1、
使用**@Resource**注解指定需要注入的实现类
@Resource(name = "userService001Impl")
private UserService userService;
2、
使用**@Qualifier**注解指定需要注入的实现类
@Autowired
@Qualifier("userService001Impl")
private UserService userService;
3、在UserService接口的两个实现类中我要需要注入的那一个加上**@Primary**注解指定优先级。
//OrderServiceImpl类:
@Autowired
private UserService userService;
//UserService001Impl 类:
@Service
@Primary
public class UserService001Impl implements UserService {
public void add() {
System.out.println("UserService001Impl");
}
}
@Qualifier 和 @Primary的区别就是前者需要指定名字,而且使用的位置不一样。
需要注意的地方:
1、
照着敲报了一个错:NoSuchBeanDefinitionException: No bean named ‘orderServiceImpl’ available
没有这个bean?
原因是配置类中没有加上扫包注解:@ComponentScan(“com.jiyu.v4”)
2、
即使使用了 @Qualifier和@Resource注解还是报错
No qualifying bean of type ‘com.jiyu.v4.service.UserService’ available: expected single matching bean but found 2: userService001Impl,userService002Impl
原因是:bean名我使用了和类名相同的名字所以注入失败了,
应该是这样:首字母小写
@Qualifier(“userService001Impl”)
@Resource(name = “userService001Impl”)
这里bean名有一个规则: bean 名就要看被注解的类名, 如果类名开头是两个或两个大写字母以上, bean 名同类名完全一致;
如果开头只有一个大写字母, bean 名是类名首字母小写版.