admin管理员组文章数量:1641875
前言
在Spring容器启动之时,doRegisterBean(annotatedClass, null, null, null)的作用是向Spring容器中注入配置类bean。然而,Spring是可以进行条件注入的(通过@Conditional注解实现),这样一来就会有判断要不要注入的需求,那么如何判断一个bean要不要注入Spring容器呢?----下文的shouldSkip方法便提供了解决方法。
1.1
org.springframework.context.annotation.ConditionEvaluator#shouldSkip方法源码如下:
/**
* Determine if an item should be skipped based on {@code @Conditional} annotations.
* 基于@Conditional标签判断该item是否要跳过
* @param metadata the meta data
* @param phase the phase of the call
* @return if the item should be skipped
*/
//此方法前面的方法传入的参数一般是(metadata,null)
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
//metadata为null或者配置类中不存在@Conditional标签
//详见!metadata.isAnnotated方法的内部代码
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
//下面代码块,采用了递归方式,第一次执行的时候,phase为null,向下执行
if (phase == null) {
//下面的判断逻辑,需要进入ConfigurationClassUtils.isConfigurationCandidate方法内部,见下1.2节
//主要的逻辑如下:
//1.metadata是AnnotationMetadata类的一个实例
//2.待注入的bean中使用了@Configuration注解
//3.待注入的bean不是一个接口
//4.待注入的bean中包含@Component @ComponentScan @Import @ImportResource中任意一个
//5.待注入的bean中含有@Bean注解
//只要满足1、2 或者 1、3 或者1、4 或者1、5则会进入下面的if判断语句中,继续递归
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
//getConditionClasses(metadata)方法可以得到@Conditional注解后面value数组
for (String conditionClass : conditionClasses) {
//
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
//通过Spring内部的AnnotationAwareOrder-Comparator定义的规则进行排序,有待继续探索
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
//requiredPhase只可能为null或者是ConfigurationCondition的一个实例对象
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
//此逻辑为:1.requiredPhase不是ConfigurationCondition的实例
//2.phase==requiredPhase,从上述的递归可知:phase可为ConfigurationPhase.PARSE_CONFIGURATION或者ConfigurationPhase.REGISTER_BEAN
//3.condition.matches(this.context, metadata)返回false
//如果1、2或者1、3成立,则在此函数的上层将阻断bean注入Spring容器
return true;
}
}
return false;
}
1.2
ConfigurationClassUtils.isConfigurationCandidate方法源码:
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
}
对isFullConfigurationCandidate和isLiteConfigurationCandidate方法的分析分别见下1.3节与1.4接
1.3
isFullConfigurationCandidate源码如下:
/**
* Check the given metadata for a full configuration class candidate
* (i.e. a class annotated with {@code @Configuration}).
* @param metadata the metadata of the annotated class
* @return {@code true} if the given class is to be processed as a full
* configuration class, including cross-method call interception
*/
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
//metadata.isAnnotated源码:
/**
* Check the given metadata for a full configuration class candidate
* (i.e. a class annotated with {@code @Configuration}).
* @param metadata the metadata of the annotated class
* @return {@code true} if the given class is to be processed as a full
* configuration class, including cross-method call interception
*/
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
//判断是否含有@Configuration注释
return metadata.isAnnotated(Configuration.class.getName());
}
1.4
isLiteConfigurationCandidate方法源码如下:
/**
* Check the given metadata for a lite configuration class candidate
* (e.g. a class annotated with {@code @Component} or just having
* {@code @Import} declarations or {@code @Bean methods}).
* @param metadata the metadata of the annotated class
* @return {@code true} if the given class is to be processed as a lite
* configuration class, just registering it and scanning it for {@code @Bean} methods
*/
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
// Do not consider an interface or an annotation...
//待注册bean不是一个接口,返回为true
if (metadata.isInterface()) {
return false;
}
// Any of the typical annotations found?
//candidateIndicators定义如下1.5,其实它是一个hashSet
//逻辑为:待注册bean中含有@Component、@ComponentScan、@Import以及@ImportResource任意一个注释,返回为true
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
try {
//待注入bean含有@Bean注释,返回为true
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
}
return false;
}
}
1.5
candidateIndicators定义以及内容如下:
private static final Set<String> candidateIndicators = new HashSet<>(8);
static {
candidateIndicators.add(Component.class.getName());
candidateIndicators.add(ComponentScan.class.getName());
candidateIndicators.add(Import.class.getName());
candidateIndicators.add(ImportResource.class.getName());
}
1.6 参考文献
【1】https://segmentfault/a/1190000017413393?utm_source=tag-newest
【2】https://www.bilibili/video/BV1tx411o77Z?p=5
【3】《Spring源码解析》
本文标签: 容器详解方法springframeworkorg
版权声明:本文标题:Spring容器启动之org.springframework.context.annotation.ConditionEvaluator#shouldSkip方法详解 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1729330340a1196311.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论