【Spring Boot 源码学习】@Conditional 条件注解

news2024/11/28 23:39:10

Spring Boot 源码学习系列

在这里插入图片描述

@Conditional 条件注解

  • 引言
  • 往期内容
  • 主要内容
    • 1. 初识 @Conditional
    • 2. @Conditional 的衍生注解
  • 总结

引言

前面的博文,Huazie 带大家从 Spring Boot 源码深入了解了自动配置类的读取和筛选的过程,然后又详解了OnClassConditionOnBeanConditionOnWebApplicationCondition 这三个自动配置过滤匹配子类实现。

在上述的博文中,我们其实已经初步涉及到了像 @ConditionalOnClass@ConditionalOnBean@ConditionalOnWebApplication 这样的条件注解,并且这些条件注解里面,我们都能看到 @Conditional 注解。

在这里插入图片描述

往期内容

在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:

Spring Boot 源码学习
Spring Boot 项目介绍
Spring Boot 核心运行原理介绍
【Spring Boot 源码学习】@EnableAutoConfiguration 注解
【Spring Boot 源码学习】@SpringBootApplication 注解
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
【Spring Boot 源码学习】自动装配流程源码解析(上)
【Spring Boot 源码学习】自动装配流程源码解析(下)
【Spring Boot 源码学习】深入 FilteringSpringBootCondition
【Spring Boot 源码学习】OnClassCondition 详解
【Spring Boot 源码学习】OnBeanCondition 详解
【Spring Boot 源码学习】OnWebApplicationCondition 详解

主要内容

本篇我们重点介绍 @Conditional 条件注解,参见如下:

1. 初识 @Conditional

我们先来看看 @Conditional 注解的源码【Spring Context 5.3.25】:

/**
 * 表示组件仅在所有指定条件匹配时才有资格注册。
 * 
 * 条件是在bean定义即将注册之前可以通过编程确定的任何状态(有关详细信息,请参阅Condition)。
 * 
 * @Conditional注解可以以以下任意方式使用:
 * 	作为类型级别的注释直接或间接地应用于带有@Component的任何类,包括@Configuration类
 * 	作为元注释,用于组合自定义注释标签
 * 	作为@Bean方法上的注释级别注解
 * 
 * 如果一个@Configuration类被标记为@Conditional,则该类的所有@Bean方法、@Import注解和@ComponentScan注解都将受到条件约束。
 *
 * @author Phillip Webb
 * @author Sam Brannen
 * @since 4.0
 * @see Condition
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

	/**
	 * 必须匹配才能注册组件的所有条件类
	 */
	Class<? extends Condition>[] value();

}

翻看上述源码,可以看到 @Conditional 条件注解是从 Spring 4.0 开始引入的,它表示组件仅在所有指定条件匹配时才有资格注册。比如,当类加载器下存在某个指定的类的时候才会对注解的类进行实例化操作。

它唯一的元素属性是接口 Condition 的数组,只有数组中指定的所有 Conditionmatches 方法都返回 true 的情况下,被注解的类才会被加载。我们前面讲到的 OnClassCondition 等类就是 Condition 的子类之一。

/**
 * 一个必须匹配才能注册的单个 Condition。
 *
 * <p> 在 bean 定义即将被注册之前立即进行检查,并可以根据在该点可以确定的任何标准自由否决注册。
 *
 * <p> 条件必须遵循与 BeanFactoryPostProcessor 相同的限制,并确保不要与 bean 实例进行交互。
 * 对于与 @Configuration beans交互的更细粒度的控制,请考虑实现 ConfigurationCondition 接口。
 *
 * @author Phillip Webb
 * @since 4.0
 * @see ConfigurationCondition
 * @see Conditional
 * @see ConditionContext
 */
@FunctionalInterface
public interface Condition {

	/**
	 * 确定条件是否匹配。
	 * @param context 条件上下文
	 * @param metadata 正在检查的 AnnotationMetadata 或 MethodMetadata 的元数据
	 * @return 如果条件匹配并且可以注册组件,则返回 true;否则返回 false,否决带有注解的组件的注册。
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

上述就是 Condition 接口的源码,它的 matches 方法用来确定条件是否匹配,其中两个参数分别如下:

  • ConditionContext :条件上下文,可通过该接口提供的方法来获得 Spring 应用的上下文信息,接口定义如下:

    public interface ConditionContext {
    
    	/**
    	 * 返回一个 BeanDefinitionRegistry 对象,该对象将包含如果条件匹配时应该持有的bean定义。
    	 * 如果没有可用的注册表(这种情况很少见:只有当使用 ClassPathScanningCandidateComponentProvider 时才会出现),
    	 * 则会抛出IllegalStateException异常。
    	 */
    	BeanDefinitionRegistry getRegistry();
    
    	/**
    	 * 返回一个 ConfigurableListableBeanFactory 对象,该对象将包含如果条件匹配时应该持有的bean定义,
    	 * 或者 如果bean工厂不可用(或者无法向下转型为 ConfigurableListableBeanFactory),则返回null。
    	 */
    	@Nullable
    	ConfigurableListableBeanFactory getBeanFactory();
    
    	/**
    	 * 返回当前应用程序正在运行的环境。
    	 */
    	Environment getEnvironment();
    
    	/**
    	 * 返回当前正在使用的资源加载器。
    	 */
    	ResourceLoader getResourceLoader();
    
    	/**
    	 * 返回应该用来加载额外类的 ClassLoader。如果系统类加载器不可访问,则返回null。
    	 */
    	@Nullable
    	ClassLoader getClassLoader();
    
    }
    
  • AnnotatedTypeMetadata :该接口提供了访问特定类或方法的注解功能,并且不需要加载类,可以用来检查带有 @Bean 注解的方法上是否还有其他注解。

    下面我们来查看下它的源码【spring-core 5.3.25】:

    public interface AnnotatedTypeMetadata {
    	// 返回一个MergedAnnotations对象,表示该类型的注解集合。
        MergedAnnotations getAnnotations();
    	// 检查是否存在指定名称的注解,如果存在则返回true,否则返回false。
        default boolean isAnnotated(String annotationName) {
            return this.getAnnotations().isPresent(annotationName);
        }
    
    	// 下面的方法,都是用来获取指定名称注解的属性值
        @Nullable
        default Map<String, Object> getAnnotationAttributes(String annotationName) {
            return this.getAnnotationAttributes(annotationName, false);
        }
    
        @Nullable
        default Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
            MergedAnnotation<Annotation> annotation = this.getAnnotations().get(annotationName, (Predicate)null, MergedAnnotationSelectors.firstDirectlyDeclared());
            return !annotation.isPresent() ? null : annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));
        }
    
        @Nullable
        default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName) {
            return this.getAllAnnotationAttributes(annotationName, false);
        }
    
        @Nullable
        default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {
            Adapt[] adaptations = Adapt.values(classValuesAsString, true);
            return (MultiValueMap)this.getAnnotations().stream(annotationName).filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes)).map(MergedAnnotation::withNonMergedAttributes).collect(MergedAnnotationCollectors.toMultiValueMap((map) -> {
                return map.isEmpty() ? null : map;
            }, adaptations));
        }
    }
    

2. @Conditional 的衍生注解

Spring Bootautoconfigure 项目中提供了各类基于@Conditional 注解的衍生注解,它们均位于 spring-boot-autoconfigure 项目的 org.springframework.boot.autoconfigure.condition 包下,如下图所示:。

在这里插入图片描述

上述有好几个条件注解,我们已经接触过了,下面我们再仔细介绍一下:

  • @ConditionalOnBean:当容器中有指定 Bean 的条件下。

  • @ConditionalOnClass:当 classpath 类路径下有指定类的条件下。

  • @ConditionalOnCloudPlatform:当指定的云平台处于 active 状态时。

  • @ConditionalOnExpression:基于 SpEL 表达式的条件判断。

  • @ConditionalOnJava:基于 JVM 版本作为判断条件。

  • @ConditionalOnJndi:在 JNDI 存在的条件下查找指定的位置。

  • @ConditionalOnMissingBean:当容器里没有指定 Bean 的条件。

  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下。

  • @ConditionalOnNotWebApplication:当项目不是一个 Web 项目的条件下。

  • @ConditionalOnProperty:当指定的属性有指定的值的条件下。

  • @ConditionalOnResource:类路径是否有指定的值。

  • @ConditionalOnSingleCandidate:当指定的 Bean 在容器中只有一个,或者有多个但是指定了首选的 Bean

  • @ConditionalOnWebApplication:当项目是一个 Web 项目的条件下

如果我们仔细观察这些注解的源码,很快会发现它们其实都组合了@Conditional 注解,不同的是它们在注解中指定的条件(Condition)不同。

下面我们以前面博文中了解过的 @ConditionalOnWebApplication 为例,来对衍生条件注解进行一个简单的分析:

/**
 * 用于条件性地匹配应用程序是否为Web应用程序。默认情况下,任何Web应用程序都会匹配,但可以通过type()属性进行缩小范围。
 *
 * @author Dave Syer
 * @author Stephane Nicoll
 * @since 1.0.0
 */
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnWebApplicationCondition.class)
public @interface ConditionalOnWebApplication {
	// 所需的web应用类型
	Type type() default Type.ANY;
	// 可选应用类型枚举
	enum Type {	
		// 任何类型
      	ANY,
      	// 基于servlet的web应用
      	SERVLET,
      	// 基于reactive的web应用
      	REACTIVE
	}
}

通过查看 @ConditionalOnWebApplication 注解的源码,我们发现它的确组合了 @Conditional 注解,并且指定了对应的 ConditionOnWebApplicationCondition。该类继承自 SpringBootCondition 并实现 AutoConfigurationImportFilter 接口。

有关 OnWebApplicationCondition 类的详细介绍,请查看笔者的《【Spring Boot 源码学习】OnWebApplicationCondition 详解》,

了解了条件类的相关内容后,我们可以用如下图来表示 Condition 接口相关功能及实现类:

在这里插入图片描述

总结

本篇我们介绍 @Conditional 条件注解及其衍生注解,至此有关自动配置装配的流程已经基本介绍完毕。

虽然我们从源码角度对自动装配流程有了清晰的认识,但还是不能熟练地运用。那么下篇博文,我们将以 Spring Boot 内置的 http 编码功能为例来分析一下整个自动配置的过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1096296.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nodejs+vue百鸟全科赏析网站

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

Linux性能优化--性能工具:特定进程内存

5.0 概述 本章介绍的工具使你能诊断应用程序与内存子系统之间的交互&#xff0c;该子系统由Linux内核和CPU管理。由于内存子系统的不同层次在性能上有数量级的差异&#xff0c;因此&#xff0c;修复应用程序使其有效地使用内存子系统会对程序性能产生巨大的影响。 阅读本章后&…

ubuntu 怎样查看隐藏文件

1.通过界面可视化方式 鼠标点击进入该待显示的文件路径&#xff0c;按下ctrl h 刷新&#xff0c;则显示隐藏文件 2. 通过控制台命令行 若使用命令行&#xff0c;则使用命令&#xff1a;ls -a 显示所有文件&#xff0c;也包括隐藏文件

MPNN 模型:GNN 传递规则的实现

首先&#xff0c;假如我们定义一个极简的传递规则 A是邻接矩阵&#xff0c;X是特征矩阵&#xff0c; 其物理意义就是 通过矩阵乘法操作&#xff0c;批量把图中的相邻节点汇聚到当前节点。 但是由于A的对角线都是 0.因此自身的节点特征会被过滤掉。 图神经网络的核心是 吸周围…

【数据结构与算法】堆排序(向下和向上调整)、TOP-K问题(超详细解读)

前言&#xff1a; &#x1f4a5;&#x1f388;个人主页:​​​​​​Dream_Chaser&#xff5e; &#x1f388;&#x1f4a5; ✨✨专栏:http://t.csdn.cn/oXkBa ⛳⛳本篇内容:c语言数据结构--堆排序&#xff0c;TOP-K问题 目录 堆排序 1.二叉树的顺序结构 1.1父节点和子节点…

Ubuntu:ESP-IDF 开发环境配置【保姆级】

物联网开发学习笔记——目录索引 参考官网&#xff1a;ESP-IDF 物联网开发框架 | 乐鑫科技 ESP-IDF 是乐鑫官方推出的物联网开发框架&#xff0c;支持 Windows、Linux 和 macOS 操作系统。适用于 ESP32、ESP32-S、ESP32-C 和 ESP32-H 系列 SoC。它基于 C/C 语言提供了一个自给…

EmoTalk: Speech-Driven Emotional Disentanglement for 3D Face Animation

问题:现存的方法经常忽略面部的情感或者不能将它们从语音内容中分离出来。 方法:本文提出了一种端到端神经网络来分解语音中的不同情绪,从而生成丰富的 3D 面部表情。 1.我们引入了情感分离编码器(EDE),通过交叉重构具有不同情感标签的语音信号来分离语音中的情感和内容。…

MySQL 的下载与安装

MySQL 的下载 https://cdn.mysql.com/archives/mysql-5.7/mysql-5.7.30-1.el7.x86_64.rpm-bundle.tar 将下载的数据包拉到虚拟机的linux系统的主文件夹下,创建一个MySQL文件存放 安装MySQL 1、解压数据包 tar -xvf mysql-5.7.30-1.el7.x86_64.rpm-bundle.tar -x: 表示解压…

【LLM】浅谈 StreamingLLM中的attention sink和sink token

前言 Softmax函数 SoftMax ( x ) i e x i e x 1 ∑ j 2 N e x j , x 1 ≫ x j , j ∈ 2 , … , N \text{SoftMax}(x)_i \frac{e^{x_i}}{e^{x_1} \sum_{j2}^{N} e^{x_j}}, \quad x_1 \gg x_j, j \in 2, \dots, N SoftMax(x)i​ex1​∑j2N​exj​exi​​,x1​≫xj​,j∈2,……

智慧公厕:提升城市形象的必备利器

智慧公厕是什么&#xff1f;智慧公厕基于物联网的技术基础&#xff0c;整合了互联网、人工智能、大数据、云计算、区块链、5G/4G等最新技术&#xff0c;针对公共厕所日常建设、使用、运营和管理的全方位整体解决方案。智慧公厕广泛应用于旅游景区、城市公厕、购物中心、商业楼宇…

2 files found with path ‘lib/armeabi-v7a/liblog.so‘ from inputs:

下图两个子模块都用CMakeLists.txt引用了android的log库&#xff0c;编译后&#xff0c;在它们的build目录下都有liblog.so的文件。 四个CPU架构的文件夹下都有。 上层模块app不能决定使用哪一个&#xff0c;因此似乎做了合并&#xff0c;路径就是报错里的哪个路径&#xff0c…

WSL Ubuntu 22.04.2 LTS 安装paddle踩坑日记

使用conda安装paddlepaddle-gpu: conda install paddlepaddle-gpu2.5.1 cudatoolkit11.7 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/Paddle/ -c conda-forge 等待安装... 报错处理&#xff1a; (1)(1)PreconditionNotMetError: Cannot load cudnn shared libr…

[BigData:Hadoop]:安装部署篇

文章目录 一&#xff1a;机器103设置密钥对免密登录二&#xff1a;机器102设置密钥对免密登录三&#xff1a;机器103安装Hadoop安装包3.1&#xff1a;wget拉取安装Hadoop包3.2&#xff1a;解压移到指定目录3.2.1&#xff1a;解压移动路径异常信息3.2.2&#xff1a;切换指定目录…

Docker容器端口暴露方式

【Bridge 模式】 当 Docker 进程启动时&#xff0c;会在主机上创建一个名为docker0的虚拟网桥&#xff0c;此主机上启动的 Docker 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似&#xff0c;这样主机上的所有容器就通过交换机连在了一个二层网络中。从 doc…

启动速度提升 10 倍:Apache Dubbo 静态化方案深入解析

作者&#xff1a;华钟明 文章摘要&#xff1a; 本文整理自有赞中间件技术专家、Apache Dubbo PMC 华钟明的分享。本篇内容主要分为五个部分&#xff1a; -GraalVM 直面 Java 应用在云时代的挑战 -Dubbo 享受 AOT 带来的技术红利 -Dubbo Native Image 的实践和示例 -Dubbo…

050:mapboxGL加载geojson数据,同时包含点、多边形的处理示例

第050个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中加载geojson数据,既显示点又显示多边形。这个示例是显示了一种处理方式,通过过滤的方式将数据分离化,点和多边形通过两个不同的图层来加载表示。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实…

Ps:快速蒙版

快速蒙版 Quick Mask是查看和编辑选区的一种模式。 按快捷键 Q 可切换到快速蒙版模式&#xff0c;再按一次 Q 键则会退出快速蒙版模式。 或者&#xff0c;点击工具箱下方的“快速蒙版”按钮来进行切换。 也可使用菜单命令。 Ps菜单&#xff1a;选择/在快速蒙版模式下编辑 Selec…

[管理与领导-120]:IT基层管理 - 决策者和管理者的灵活变通与执著坚持的平衡

目录 前言&#xff1a; 一、决策者什么时候应该灵活多变&#xff1f;路径、方法、过程 二、决策者什么时候应该坚定坚持&#xff1f;方向、愿景、目标 三、PDCA与决策者的灵活多变与坚定坚持的平衡 前言&#xff1a; 作为执行者&#xff0c;只需要按照决策者的要求&#x…

vue3后台管理框架之技术栈

vue3全家桶技术 基础构建&#xff1a; vue3vite4TypeScript 代码格式 &#xff1a; eslintprettystylelint git生命周期钩子&#xff1a; husky css预处理器&#xff1a; sass ui库&#xff1a; element-plus 模拟数据: mock 网络请求&#xff1a; axios 路由&#xff1a; vue…

Build your own X:从零开始创造自己的技术项目 | 开源日报 No.56

codecrafters-io/build-your-own-x Stars: 206.6k License: NOASSERTION Build your own X 是一个集合了多个精心编写的、逐步指导你从零开始创建自己喜欢的技术项目的开源教程。这是学习编程的绝佳方式。 以下是一些核心优势和关键特性&#xff1a; 提供了各种不同领域 (如…