springboot注解–基础–2.4–ConditionalOnMissingBean、ConditionalOnBean、ConditionalOnSingleCandidate
代码位置
https://gitee.com/DanShenGuiZu/learnDemo/tree/master/annotation-learn/annotation-learn1
1、介绍
-
ConditionalOnMissingBean
- 该注解规定的类不存在于 spring容器中时,使用该注解的config或者bean声明才会被实例化到容器中
-
ConditionalOnBean
- 该注解规定的类存在于 spring容器中时,使用该注解的config或者bean声明才会被实例化到容器中
-
ConditionalOnSingleCandidate
- 当指定Bean在容器中只有一个,或者虽然有多个但是指定首选Bean,使用该注解的config或者bean声明才会被实例化到容器中
1.2、ConditionalOnBean注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
/**
* 需要作为条件的类Class对象数组
*/
Class<?>[] value() default {};
/**
* 需要作为条件的类Name,Class.getName()
*/
String[] type() default {};
/**
* (用指定注解修饰的bean)条件所需的注解类
*/
Class<? extends Annotation>[] annotation() default {};
/**
* spring容器中bean的名字
*/
String[] name() default {};
/**
* 搜索容器层级:当前容器,父容器,默认所有
*/
SearchStrategy search() default SearchStrategy.ALL;
/**
*
* 可能在其泛型参数中包含指定bean类型的其他类
*/
Class<?>[] parameterizedContainer() default {};
1.3、ConditionalOnMissingBean注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {
/**
* 需要作为条件的类Class对象数组
*/
Class<?>[] value() default {};
/**
* 需要作为条件的类Name,Class.getName()
*/
String[] type() default {};
/**
* (用指定注解修饰的bean)条件所需的注解类
*/
Class<? extends Annotation>[] annotation() default {};
/**
* spring容器中bean的名字
*/
String[] name() default {};
/**
* 搜索容器层级:当前容器,父容器,默认所有
*/
SearchStrategy search() default SearchStrategy.ALL;
/**
*
* 可能在其泛型参数中包含指定bean类型的其他类
*/
Class<?>[] parameterizedContainer() default {};
/**
* 标识匹配bean时应忽略的bean的class类型。
*/
Class<?>[] ignored() default {};
/**
* 标识匹配项时应忽略的bean的class类型名称
*/
String[] ignoredType() default {};
}
1.4、ConditionalOnSingleCandidate注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnSingleCandidate {
/**
* 需要作为条件的类Class对象
*/
Class<?> value() default Object.class;
/**
* 需要作为条件的类Name,Class.getName()
*/
String type() default "";
/**
* 搜索容器层级:当前容器,父容器,默认所有
*/
SearchStrategy search() default SearchStrategy.ALL;
}
1.5、OnClassCondition类关系
2、测试
2.1、代码
@Configuration
public class TestConfig {
@Bean
@ConditionalOnMissingBean(Test1.class)
Test1 test1() {
System.out.println("---------Test1 实例化bean不存在,将Test1注册到容器中---------");
return new Test1();
}
@Bean
@ConditionalOnBean(Test1.class)
Test2 test2() {
System.out.println("---------Test1 实例化bean存在,将Test2注册到容器中---------");
return new Test2();
}
@Bean
@ConditionalOnSingleCandidate(Test1.class)
Test2 test3() {
System.out.println("---------当指定Bean在容器中只有一个,或者虽然有多个但是指定首选Bean,就注册test3到容器中---------");
return new Test2();
}
public class Test1 {
}
public class Test2 {
}
public static void main(String[] args) {
// 设置日志级别,去掉我不要的信息
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
List<Logger> loggerList = loggerContext.getLoggerList();
loggerList.forEach(logger -> {
logger.setLevel(Level.ERROR);
});
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
}
}
2.2、测试
3、原理分析
我们通过类关系图找到Condition接口有个实现抽象类SpringBootCondition,SpringBoot中所有条件注解对应的条件类都继承这个抽象类。它实现了matches方法
getMatchOutcome是个抽象方法,需要子类去实现
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConditionMessage matchMessage = ConditionMessage.empty();
MergedAnnotations annotations = metadata.getAnnotations();
//ConditionalOnBean注解 的处理方法
if (annotations.isPresent(ConditionalOnBean.class)) {
// 将 ConditionalOnBean 注解属性封装进Spec对象中
Spec<ConditionalOnBean> spec = new Spec<>(context, metadata, annotations, ConditionalOnBean.class);
// 获取匹配的的bean
MatchResult matchResult = getMatchingBeans(context, spec);
// 注解上所有的属性都不匹配
if (!matchResult.isAllMatched()) {
String reason = createOnBeanNoMatchReason(matchResult);
// 返回匹配失败的信息
return ConditionOutcome.noMatch(spec.message().because(reason));
}
// 构建匹配成功的信息
matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
matchResult.getNamesOfAllMatches());
}
//ConditionalOnSingleCandidate注解 的处理方法
if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
// 将 ConditionalOnSingleCandidate 注解属性封装进Spec对象中
Spec<ConditionalOnSingleCandidate> spec = new SingleCandidateSpec(context, metadata, annotations);
MatchResult matchResult = getMatchingBeans(context, spec);
// 注解上所有的属性都不匹配
if (!matchResult.isAllMatched()) {
// 返回匹配失败的信息
return ConditionOutcome.noMatch(spec.message().didNotFind("any beans").atAll());
}
// 如果bean不是单例或者多实例情况下,没有Primary表示,返回匹配失败
else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matchResult.getNamesOfAllMatches(),
spec.getStrategy() == SearchStrategy.ALL)) {
// 返回匹配失败的信息
return ConditionOutcome.noMatch(spec.message().didNotFind("a primary bean from beans")
.items(Style.QUOTE, matchResult.getNamesOfAllMatches()));
}
// 构建匹配成功的信息
matchMessage = spec.message(matchMessage).found("a primary bean from beans").items(Style.QUOTE,
matchResult.getNamesOfAllMatches());
}
//ConditionalOnMissingBean注解 的处理方法
if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
// 将 ConditionalOnMissingBean 注解属性封装进Spec对象中
Spec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,
ConditionalOnMissingBean.class);
// 获取匹配的的bean
MatchResult matchResult = getMatchingBeans(context, spec);
// 没有一个匹配成功,返回匹配失败
if (matchResult.isAnyMatched()) {
String reason = createOnMissingBeanNoMatchReason(matchResult);
// 返回匹配失败的信息
return ConditionOutcome.noMatch(spec.message().because(reason));
}
// 构建匹配成功的信息
matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();
}
//返回成功信息
return ConditionOutcome.match(matchMessage);
}
getMatchingBeans方法
protected final MatchResult getMatchingBeans(ConditionContext context, Spec<?> spec) {
//类加载器
ClassLoader classLoader = context.getClassLoader();
//bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 搜索容器层级:是否搜索当前容器
boolean considerHierarchy = spec.getStrategy() != SearchStrategy.CURRENT;
// 泛型参数中包含指定bean类型的其他类
Set<Class<?>> parameterizedContainers = spec.getParameterizedContainers();
// 如果搜索的是父容器
if (spec.getStrategy() == SearchStrategy.ANCESTORS) {
//获取父bean工厂
BeanFactory parent = beanFactory.getParentBeanFactory();
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent,
"Unable to use SearchStrategy.ANCESTORS");
beanFactory = (ConfigurableListableBeanFactory) parent;
}
//构建匹配结果类
MatchResult result = new MatchResult();
// 获取忽略的bean计划
Set<String> beansIgnoredByType = getNamesOfBeansIgnoredByType(classLoader, beanFactory, considerHierarchy,
spec.getIgnoredTypes(), parameterizedContainers);
// 解析注解的value,type属性
for (String type : spec.getTypes()) {
// 通过注解value,type属性,在bean工厂中获取所有匹配的bean
Collection<String> typeMatches = getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type,
parameterizedContainers);
// 删除忽略的bean
typeMatches.removeAll(beansIgnoredByType);
if (typeMatches.isEmpty()) {
// 注解value,type属性,没有匹配到bean
result.recordUnmatchedType(type);
}
else {
//注解value,type属性,匹配到bean
result.recordMatchedType(type, typeMatches);
}
}
// 解析注解的annotation属性
for (String annotation : spec.getAnnotations()) {
// 通过注解annotation属性,在bean工厂中获取所有匹配的bean
Set<String> annotationMatches = getBeanNamesForAnnotation(classLoader, beanFactory, annotation,
considerHierarchy);
// 删除忽略的bean
annotationMatches.removeAll(beansIgnoredByType);
if (annotationMatches.isEmpty()) {
// 注解annotation属性 ,没有匹配到bean
result.recordUnmatchedAnnotation(annotation);
}
else {
// 注解annotation属性 ,匹配到bean
result.recordMatchedAnnotation(annotation, annotationMatches);
}
}
// 解析注解的name属性
for (String beanName : spec.getNames()) {
// 如果忽略的属性没有name,且容器中包含name
if (!beansIgnoredByType.contains(beanName) && containsBean(beanFactory, beanName, considerHierarchy)) {
// 注解name属性 ,匹配到bean
result.recordMatchedName(beanName);
}
else {
// 注解name属性,没有匹配到bean
result.recordUnmatchedName(beanName);
}
}
//返回结果
return result;
}
hasSingleAutowireCandidate方法
private boolean hasSingleAutowireCandidate(ConfigurableListableBeanFactory beanFactory, Set<String> beanNames,
boolean considerHierarchy) {
// 单个实例或者又Primary注解,返回true
return (beanNames.size() == 1 || getPrimaryBeans(beanFactory, beanNames, considerHierarchy).size() == 1);
}