admin管理员组文章数量:1623796
注解分析
@Qualifier和@Primary都是属于spring框架下的注解,@Priority属于javax.annotation,JSR250规范。
@Primary官方文档的大概意思是,如果在自动注入的多个候选bean中,有一个primary bean的话,那么这个bean就会是自动注入的目标bean。可以作用在类和方法上
@Qualifier官方的大概意思是,自动注入的时候,使用了这个注解,那么在候选bean中,就会用这个注解指定的那个bean。作用在字段,方法,类,参数,注解上。
@Priority大概意思是说明使用的顺序,作用在参数和类上。
代码测试
新建几个类:
待注入的接口:
public interface WhichSelected {
String beanName();
}
三个实现类:
@Component
@Primary
public class PrimarySelected implements WhichSelected{
@Override
public String beanName() {
return "primarySelected";
}
}
@Component
@Priority(1)
public class PrioritySelected implements WhichSelected{
@Override
public String beanName() {
return "prioritySelected";
}
}
@Component
@Priority(2)
public class PriorityNextSelected implements WhichSelected{
@Override
public String beanName() {
return "priorityNextSelected";
}
}
注入的类:
@Component
public class TargetInject {
@Autowired
private WhichSelected whichSelected;
public void whichBean() {
System.out.println(whichSelected.beanName());
}
}
包扫描类:
@Configuration
@ComponentScan("spring.postprocessor.choseorder")
public class PackageScannerConfig {
}
测试类:
public class OrderTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PackageScannerConfig.class);
TargetInject targetInject = context.getBean(TargetInject.class);
targetInject.whichBean();
}
}
运行结果:
primarySelected
修改代码:
@Autowired
@Qualifier("priorityNextSelected")
private WhichSelected whichSelected;
结果:
priorityNextSelected
注掉//@Primary
@Component
//@Primary
public class PrimarySelected implements WhichSelected{
@Override
public String beanName() {
return "primarySelected";
}
}
结果:
prioritySelected
修改代码,去掉所有的@Qualifier,@Priority,@Primary,运行:
很明显会报错,找不到要注入的bean
再次修改:
将private WhichSelected whichSelected;改为private WhichSelected prioritySelected; 运行结果为prioritySelected
代码小结
从上面五种情况可以看出,第一优先候选bean是@Qualifier注解指定的bean,第二优先是@Primary注解的bean,第三是@Priority(1)以及其后面的顺序,最后是bean名称。
源码调试
先将代码恢复到上面最开始的状态。
我们都知道这一行代码:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PackageScannerConfig.class);
是获取IOC容器的,点到AbstractApplicationContext类里面的refresh()方法,可以看到其实创建的是一个ConfigurableListableBeanFactory,
这是一个接口,我们来到DefaultListableBeanFactory,这个类实现了这个接口。
这里讨论的注入是用@Autowired注入的,其实很多注解都是通过后置处理器实现的,@Autowired注解也是,对应的后置处理器是:AutowiredAnnotationBeanPostProcessor,
这个类实现了PriorityOrdered接口,可以自行看一下后置处理器的加载顺序,这里不讨论。注入的时机和其他创建bean初始化属性的时机都是在populateBean的时候进行的。
来到AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法
继续F8会来到AbstractAutowireCapableBeanFactory的populateBean方法,可以看到这个方法里面也是一系列的后置处理器的处理。这里只需要看一下就可以,一直按F9,到beanName是targetInject的时候停下
按F8来到AutowiredAnnotationBeanPostProcessor的inject方法,来看那一下调用栈:
继续向下走,会来到容器解决依赖这里DefaultListableBeanFactory的doResolveDependency方法,走到这里是关键
step into进去
这里就能看到候选bean的名字了,走到下一个for循环
这里是重点,第一轮淘汰,待会说到@Qualifier再点进去,看字面意思就是判断一下不是自我引用和是候选bean,其实就是这个意思,满足条件就加进去,在上面的代码情况下,会全部加进去
继续向下走,走到doResolveDependency的这里
就开始从多个候选bean里面筛选。继续向下
进到determineAutowireCandidate方法里面,其实在这个方法里面就可以看出顺序了
先是primary,然后priority,最后beanName。
继续进入方法determinePrimaryCandidate
可以看到最主要的判断方法是isPrimary,进去
点进去isPrimary
可以看到是AbstractBeanDefinition下面的一个Boolean属性,此时看一下bean定义信息:
可以看到primarySelected是一个ScannedGenericBeanDefinition,其中ScannedGenericBeanDefinition又是AbstractBeanDefinition的子类
所以肯定有这个属性信息,果然有,为true
还可以看到一些常见的属性,单例,懒加载等等。
为true,所以可以通过,来到下一步:
可以看到一种类型的bean,只能有一个primary。最后返回bean名称,将这个bean作为选中的bean注入。
点进determineHighestPriorityCandidate看是一样的,不能有同等级优先级。
这样候选bean的选取就结束了,现在加一个@Qualifier。
现在来到上面说的DefaultListableBeanFactory-》findAutowireCandidates的这个for循环:
继续深入:isAutowireCandidate(candidate, descriptor) -》isAutowireCandidate(beanName, descriptor, getAutowireCandidateResolver()) -》isAutowireCandidate(beanName, getMergedLocalBeanDefinition(beanDefinitionName), descriptor, resolver)-》QualifierAnnotationAutowireCandidateResolver的isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor)
进入:checkQualifiers
这里就是检查@Qualifier这个注解
如果是@Qualifier,继续下一步
如果beanName和@Qualifier一致,就会返回true,上面的那个for循环就能加进去,最终的result只有一个元素:
因为只有一个元素,所以就不会来到后面的检查,因为:
大于1才会后面的检查。
至此,整个过程就结束了。
验证
可以看到容器DefaultListableBeanFactory的determineAutowireCandidate方法是protected,所以我们可以继承这个容器,自己来写选取顺序,来验证上面的调试。
把代码考过来,交换priorityCandidate和primaryCandidate的顺序:
public class MyListableBeanFactory extends DefaultListableBeanFactory {
@Override
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
return null;
}
}
去掉@Qualifier,修改测试方法:
public class OrderTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(new MyListableBeanFactory());
context.register(PackageScannerConfig.class);
context.refresh();
TargetInject targetInject = context.getBean(TargetInject.class);
targetInject.whichBean();
}
}
运行,可以看到输出的结果是:
prioritySelected
和之前的结果不一样,和我们改完的代码逻辑一致,说明调试都是正确的。
补充一点,AutowiredAnnotationBeanPostProcessor会作用于三种注解:@Autowired,@Value和JSR330的@Inject:
个人博客:https://robinted.github.io/
csdn 地址:https://blog.csdn/you_and_dream
原创链接:https://blog.csdn/you_and_dream/article/details/103247238
本文标签: 源码顺序PrimaryqualifierPriority
版权声明:本文标题:从源码分析@Qualifier,@Primary,@Priority的候选顺序 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1728897224a1178568.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论