Spring容器启动之org.springframework.context.annotation.ConditionEvaluator#shouldSkip方法详解

SpringBoot集成kafka全面实战 本文是SpringBoot+Kafka的实战讲解,如果对kafka的架构原理还不了解的读者,建议先看一下《大白话kafka架构原理》、《秒懂kafka HA(高可用)》两篇文章。 一、生产者实践 普通生产者 带回调的生产者 自定义分区器 kafka事务提交 二、消费者实践 简单消费 指定topic、partition、offset消费 ... 阅读详情

前言

在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.com/a/1190000017413393?utm_source=tag-newest

【2】https://www.bilibili.com/video/BV1tx411o77Z?p=5

【3】《Spring源码解析》

EBS开发_离散工单创建API --以下代码于20171213在TONY环境中实现 DECLARE     l_iface_rec    wip.wip_job_schedule_interface%ROWTYPE; --工单任务接口表     l_group_id     NUMBER;     l_returnstatus VARCHAR2(40);     l_errormsg     VARCHAR2(2000 阅读详情

相关推荐

Docker启动安装nacos(详情讲解,全网最细)

docker安装nacos保姆级教程

ilvjiale的博客 8万+

Java8新特性及实战视频教程完整版

Java8新特性及实战视频教程完整版Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda 表达式可以使代码变的更加简洁紧凑。Java8实战视频-01让方法参数具备行为能力Java8实战视频-02Lambda表达式初探Java8实战视频-03Lambda语法精讲Java8实战视频-04Lambda使用深入解析Java8实战视频-05Lambda方法推导详细解析-上.wmvJava8实战视频-06Lambda方法推导详细解析-下Java8实战视频-07Stream入门及Stream在JVM中的线程表现Java8实战视频-08Stream知识点总结Stream源码阅读Java8实战视频-09如何创建Stream上集Java8实战视频-10如何创建Stream下集.wmvJava8实战视频-11Stream之filter,distinct,skip,limit,map,flatmap详细介绍Java8实战视频-12Stream之Find,Match,Reduce详细介绍Java8实战视频-13NumericStream的详细介绍以及和Stream之间的相互转换Java8实战视频-14Stream综合练习,熟练掌握API的用法Java8实战视频-15在Optional出现之前经常遇到的空指针异常.wmvJava8实战视频-16Optional的介绍以及API的详解Java8实战视频-17Optional之flatMap,综合练习,Optional源码剖析Java8实战视频-18初识Collector体会Collector的强大Java8实战视频-19Collector使用方法深入详细介绍-01Java8实战视频-20Collector使用方法深入详细介绍-02Java8实战视频-21Collector使用方法深入详细介绍-03.wmvJava8实战视频-22Collector使用方法深入详细介绍-04Java8实战视频-23Collector原理讲解,JDK自带Collector源码深度剖析Java8实战视频-24自定义Collector,结合Stream的使用详细介绍Java8实战视频-25Parallel Stream编程体验,充分利用多核机器加快计算速度Java8实战视频-26Fork Join框架实例深入讲解Java8实战视频-27Spliterator接口源码剖析以及自定义Spliterator实现一个Stream.wmvJava8实战视频-28Default方法的介绍和简单的例子Java8实战视频-29Default方法解决多重继承冲突的三大原则详细介绍Java8实战视频-30多线程Future设计模式原理详细介绍,并且实现一个Future程序Java8实战视频-31JDK自带Future,Callable,ExecutorService介绍Java8实战视频-32实现一个异步基于事件回调的Future程序.wmvJava8实战视频-33CompletableFuture用法入门介绍Java8实战视频-34CompletableFuture之supplyAsync详细介绍Java8实战视频-35CompletableFuture流水线工作,join多个异步任务详细讲解Java8实战视频-36CompletableFuture常用API的重点详解-上Java8实战视频-37CompletableFuture常用API的重点详解-下Java8实战视频-38JDK老DateAPI存在的问题,新的DateAPI之LocalDate用法及其介绍.wmvJava8实战视频-39New Date API之LocalTime,LocalDateTime,Instant,Duration,Period详细介绍Java8实战视频-40New Date API之format和parse介绍

手把手教你用STM32硬件SPI驱动BMI088陀螺仪(附完整代码)

本文提供了一份详尽的STM32硬件SPI驱动BMI088陀螺仪的实战指南。内容涵盖从硬件连接、SPI底层配置、驱动层封装到设备初始化、数据读取与同步策略,并深入探讨了数据处理、滤波融合及温度补偿等核心技巧,旨在帮助开发者构建稳定高效的IMU驱动框架,解决BMI088应用中常见的挑战。

quiet的专栏 529

《Spring 高手系列》(@Conditional)笔记

《Spring 高手系列》(@Conditional)笔记

CERTAINTY的博客 573

基于ABCDRez的激光谐振腔设计与热透镜效应仿真实践

本文详细介绍了如何利用ABCDRez代码包进行激光谐振腔设计与热透镜效应仿真。通过ABCD矩阵理论和高斯光束q参数,该工具能有效模拟热透镜动态变化对腔稳定性的影响,指导腔型优化与热补偿设计,是固体激光器预研与调试的高效辅助手段。

weixin_29093017的博客 290

Android12 适配 usb 触屏

在 Android 系统中,输入设备 IDC(Input Device Configuration)设备描述文件(.idc)是用于配置和定义输入设备行为和属性的文本文件。 该文件通常在`/system/usr/idc/` 或 `/vendor/usr/idc/`,具体位置因芯片厂商SDK而异。一般情况此类文件是预置到系统,开发者 root 权限才能修改这些文件。输入设备 IDC 设备描述文件在 Android 系统中起到了识别、配置、映射和定制输入设备的作用,使得系统能够准确解析和处理各种输入设备的事件,提

weixin_35723192的博客 1231

Spring中@Condition注解用法

在这个示例中,MyCondition 中的 matches() 方法将根据 someValue 的值以及其他可能的环境因素来决定是否创建 myBean。在这个示例中,@ConditionalOnClass(SpringBootTest.class) 注解告诉 Spring Boot,只有当 SpringBootTest 类存在于类路径中时,才创建 myBean。一般来说,我们可以通过检查类路径上的某个类是否存在,或者某个系统属性是否存在,或者某个 Spring Bean 是否可用等等来实现自己的条件。

zhao_god的专栏 636

CesiumForUnreal实现地形等高线效果

CesiumForUnreal实现地形等高线效果

专注GIS开发 3437

Spring框架注解式开发(IDEA)——关于Conditional注解的具体使用(超详细)

Spring框架,IOC容器,Conditional

weixin_59015876的博客 555

Linux(31)Rockchip RK3568 Ubuntu22.04上部署 Docker: 问题与解决方案

本博客在总结这些问题及其解决方案,为遇到类似问题的兄弟提供参考,如果我后续有碰到其他Docker 问题也会在此更新补充。

我其实什么都不会 1645

【YOLOv8科研级优化】基于YOLOv9的GELAN模块重构C2f架构,显著提升模型精度与推理效率

打开确保模型解析器能识别GELANBlock模块。通过将YOLOv9的GELAN模块集成到YOLOv8的C2f模块中,我们实现了一个“强特征表达+高效计算”的目标检测模型。这个改进不仅在工程上能提升复杂场景下的检测效果,更在科研上提供了“多分支特征融合”的创新思路——这种思路可以延伸到其他检测网络(如Faster R-CNN、SSD)的改进中,帮你在论文中打造独特的研究点。

FJN110的博客 111

org.springframework.context.annotation.Condition 这个类有什么作用?

org.springframework.context.annotation.Condition 这个类有什么作用?

m0_72926194的博客 776

如何在飞腾平台上安装Ubuntu操作系统

注意: 若主板上配置的是NVME硬盘,在进行内核配置时,需要将内核的NEME驱动勾选上,否则移植内核时,无法找到文件系统,进不去操作系统。可以通过rufus软件将镜像做到U盘中,本次使用版本为Rufus 3.9.124 ,其他版本也可以。不要下载live版本的,没有准备网络环境,是一个头疼的事情,笔者暂时没有实现网络安装。将U盘接到主板usb口上,接上串口,显示器,,必需串口有打印才可以安装。可以通过dd命令,将iso安装到U盘。安装的是最小系统,缺少很多命令,需要联网更新,或则更换飞腾专用内核。

技术联盟 2645

Spring Boot @Conditional 注解

目录 前言 Spring Boot 版本 @Conditional Condition接口 ConditionContext接口 如何自定义Condition? 条件判断在什么时候执行? 多个Condition的执行顺序 Spring Boot中常用的一些注解 总结 前言 不知道大家在使用Spring Boot开发的日常中有没有用过@Conditionalxxx注解,比如@ConditionalOnM

qq_24692021的博客 890

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Spring注解开发(三)——@Conditional(SpringBoot底层大量使用到的注解)

@Conditional :按照一定的条件进行判断,满足条件才给容器中注册bean,这也是springboot底层大量使用的注解 package com.cjian.config; import com.cjian.bean.Person; import com.cjian.condition.LinuxCondition; import com.cjian.condition.WindowsCondition; import org.springframework.context.ann..

cj_eryue的博客 404

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

09-自动配置--@Condition注解

Condition注解用于选择性加载Bean时候使用(相当于条件判断) 1.创建一个Bean,这里创建了一个User 2.写User的配置类UserConfig import com.example.demo.condition.ClassCondition; import com.example.demo.domain.User; import org.springframework.context.annotation.Bean; import org.springframework.co...

1388

java Condition小解

1、Condition是org.springframework.context.annotation.Condition下的一个接口 2、通过自定义某个类来实现这个接口,返回Boolean值。 public class WindowsCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { .

aSmart_Q的博客 358

【spring源码解析】SpringAOP 框架原理

SpringAOP框架与实现原理 一 什么是AOP Aop面向切面编程,使用AOP我们可以对类似于日志,风控等系统需求进行模块化组织。简化系统需求与实现之间的对比关系。进而使得整个系统的实现更具模块化。使用传统的方式我们无法对类似日志,安全检查,事务管理等的横切关注点进行组织和实现。所以AOP引入了Aspect的概念。用来以模块化的方式对系统进行组织和封装。简单的说就是一些所有业务操作的公共操作。 二 SpringAOP的公民 2.1 joinPoint 连接点 系统运行之前AOP...

worn_xiao的博客 816

org.springframework.context.annotation.Condition

自定义配置,通过这个配置,来控制启动项目的时候是否启动mqtt。

TOOZOOY的博客 193

springboot注解--基础--2.1--Conditional

只有满足条件的类A才能注册到容器中类A必须实现Conditional接口,因为注解的value是Condition的子类或实现类。

zhou920786312的博客 236

Spring注解驱动开发-容器上下文(AnnotationConfigApplicationContext)的创建

1、org.springframework.context.annotation.AnnotationConfigApplicationContext.AnnotationConfigApplicationContext(Class<?>...) /** * Create a new AnnotationConfigApplicationContext, deriving bean definitions * from the given annotated classes and ..

Choco1ove的博客 1422

SpringBoot自定义Condition注解实战 - 第402篇

相关历史文章(阅读本文前,您可能需要先看下之前的系列????) 国内最全的SpringBoot系列之四 享元模式:共享女友-第355篇 SpringBoot有没有学明白,就看你这些面试题是否懂?- 第389篇 Spring Boot CLI你知多少?- 第394篇 创建一个 Spring Boot 项目的4种方法,你会几种?- 第396篇 Spring Boot 项目中的 parent原来还有这么多的讲究 - 第398篇 Spring Boot条件注解 - 第400篇 >悟..

悟纤学院 6807

SpringBoot使用Junit单元测试报错

使用SpringBoot的Junit单元测试,需要引入依赖 <!-- Spring Boot Test 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope&g

chunguang.yao的博客 1万+

死磕源码系列【springboot之ConditionEvaluator#shouldSkip条件注解评估类判定是否应该跳过指定注解】

条件判定接口org.springframework.context.annotation.Condition是一个函数是接口,只有一个matchs方法用来判定是否符合指定的条件,结合@Conditional注解一起使用 @FunctionalInterface public interface Condition { /** * 判定条件是否匹配 * @param context 条件上下文 * @param metadata 类或者方法的元数据对象 */ boolean matche

OceanSky的专栏 2468

Spring.通用条件类Condition

Spring.通用条件类Condition

记录 分享 成就 1669

spring源码 - @Conditional原理及运用

spring源码 - @Condition原理及运用

lin000_0的博客 557

14-SpringBoot自动配置-Condition

14-SpringBoot自动配置-Condition前言我们在前面的篇章基本上已经熟悉了怎么使用SpringBoot,但是呢。对于SpringBoot的一些高级的特性 或者 底层原理还是...

DevOps海洋的渔夫@专栏 899
上一篇: java基本数据类型传递与引用传递区别详解
下一篇: Spring源码分析之Scope注解处理
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值