Spring Conditional原理与实例

2024-04-21 18:48

本文主要是介绍Spring Conditional原理与实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1. 简介
    • 2. 自定义Condition
    • 3. @Conditional的原理
    • 4. 当Condition遇上SpringBoot

1. 简介

Spring4开始添加了一个Condition接口:

@FunctionalInterface
public interface Condition {boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

condition就是条件的意思,就是检查条件是否满足,检查什么信息的什么条件呢?

信息是从ConditionContext条件上下文中获取:

  1. BeanDefinitionRegistry:BeanDefinition注册中心
  2. ConfigurableListableBeanFactory:Spring容器
  3. Environment:环境、包括环境变量、环境属性、系统变量等
  4. ResourceLoader:资源加载器
  5. ClassLoader:类加载器

条件是从AnnotatedTypeMetadata注解元数据获取,所以一看这个接口就可以猜到它是专门为注解扫描准备的,所以还配套了一个@Conditional注解。

如果上面的说明有点抽象,那我们下面看一个简单的例子来加强理解。

2. 自定义Condition

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;public class MomCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {String dw = conditionContext.getEnvironment().getProperty("带娃");return "mom".equalsIgnoreCase(dw);}
}

非常简单,继承Condition接口,实现matches方法,根据环境、容器等信息检查是否满足条件,如果满足返回true,不满足就返回false。

上面的例子就是检查环境属性中有没有"带娃"这个属性,如果有并且等于"mom"则说明满足条件。

那这个Condition到底咋用呢?

接下来,就该@Conditional这个注解上场发挥点作用了。

3. @Conditional的原理

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import vip.mycollege.spring.condition.MomCondition;
import vip.mycollege.spring.condition.PapaCondition;@Configuration
public class ConditionConfig {@Conditional(MomCondition.class)@Beanpublic String mom(){return "allen";}@Conditional(PapaCondition.class)@Beanpublic String papa(){return "bob";}
}

@Conditional注解可以放在方法和类上。

  1. 放在方法上和@Bean一起使用,表示如果@Conditional注解的参数类matches方法为true这创建这个Bean实例,否则不创建。
  2. 放在类上结合@Configuration、@ComponentScan判断被注解的类是否需要创建

Spring具体逻辑入口:

  1. ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod:处理@Bean
  2. ConfigurationClassParser.processConfigurationClass(ConfigurationClass):处理@Configuration
  3. ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClass, SourceClass):处理@ComponentScan

处理Condition具体逻辑实现的类与方法:

ConditionEvaluator#shouldSkip

上面的Condition可以通过下面的代码做为启动入口测试一下:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import vip.mycollege.spring.config.ConditionConfig;public class AnnotationStart {public static void main(String[] args) {System.setProperty("带娃","papa");System.setProperty("带娃","mom");AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);System.out.println(context.containsBean("mom"));System.out.println(context.containsBean("papa"));}
}

4. 当Condition遇上SpringBoot

Spring中的Condition看似平平无奇,但是这个平平无奇指的是古天乐的那个平平无奇。

不信,你看当Condition遇上SpringBoot之后发生了怎样的奇迹。

从此,妈妈再也不用担心我写个Hello World都要研究半天配置和依赖了。

SpringBoot的Condition核心是:SpringBootCondition

就是用模板方法模式封装了一下,主要是为了记录日志和做Condition匹配报告输出。

在SpringBoot中自定义Condition,只需要继承SpringBootCondition,然后基本上就是把matches逻辑放在getMatchOutcome方法中就可以了。

SpringBoot中一些Condition:

Conditional注解作用
@ConditionalOnJndi在JNDI存在的条件下查找指定的位置
@ConditionalOnBean当容器里有指定Bean的条件下
@ConditionalOnJava基于JVM版本作为判断条件
@ConditionalOnClass当类路径下有指定的类的条件下
@ConditionalOnProperty指定的属性是否有指定的值
@ConditionalOnResource类路径是否有指定的值
@ConditionalOnExpression基于SpEL表达式为true的时候作为判断条件才去实例化
@ConditionalOnMissingBean当容器里没有指定Bean的情况下
@ConditionalOnMissingClass当容器里没有指定类的情况下
@ConditionalOnWebApplication当前项目时Web项目的条件下
@ConditionalOnOnSingleCandidate当指定Bean在容器中只有一个,或者有多个但是指定首选的Bean
@ConditionalOnNotWebApplication当前项目不是Web项目的条件下

这篇关于Spring Conditional原理与实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

java中long的一些常见用法

《java中long的一些常见用法》在Java中,long是一种基本数据类型,用于表示长整型数值,接下来通过本文给大家介绍java中long的一些常见用法,感兴趣的朋友一起看看吧... 在Java中,long是一种基本数据类型,用于表示长整型数值。它的取值范围比int更大,从-922337203685477

java Long 与long之间的转换流程

《javaLong与long之间的转换流程》Long类提供了一些方法,用于在long和其他数据类型(如String)之间进行转换,本文将详细介绍如何在Java中实现Long和long之间的转换,感... 目录概述流程步骤1:将long转换为Long对象步骤2:将Longhttp://www.cppcns.c

SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程

《SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程》LiteFlow是一款专注于逻辑驱动流程编排的轻量级框架,它以组件化方式快速构建和执行业务流程,有效解耦复杂业务逻辑,下面给大... 目录一、基础概念1.1 组件(Component)1.2 规则(Rule)1.3 上下文(Conte

SpringBoot服务获取Pod当前IP的两种方案

《SpringBoot服务获取Pod当前IP的两种方案》在Kubernetes集群中,SpringBoot服务获取Pod当前IP的方案主要有两种,通过环境变量注入或通过Java代码动态获取网络接口IP... 目录方案一:通过 Kubernetes Downward API 注入环境变量原理步骤方案二:通过

Springboot整合Redis主从实践

《Springboot整合Redis主从实践》:本文主要介绍Springboot整合Redis主从的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言原配置现配置测试LettuceConnectionFactory.setShareNativeConnect

Java中Map.Entry()含义及方法使用代码

《Java中Map.Entry()含义及方法使用代码》:本文主要介绍Java中Map.Entry()含义及方法使用的相关资料,Map.Entry是Java中Map的静态内部接口,用于表示键值对,其... 目录前言 Map.Entry作用核心方法常见使用场景1. 遍历 Map 的所有键值对2. 直接修改 Ma

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

关于跨域无效的问题及解决(java后端方案)

《关于跨域无效的问题及解决(java后端方案)》:本文主要介绍关于跨域无效的问题及解决(java后端方案),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录通用后端跨域方法1、@CrossOrigin 注解2、springboot2.0 实现WebMvcConfig

Java SWT库详解与安装指南(最新推荐)

《JavaSWT库详解与安装指南(最新推荐)》:本文主要介绍JavaSWT库详解与安装指南,在本章中,我们介绍了如何下载、安装SWTJAR包,并详述了在Eclipse以及命令行环境中配置Java... 目录1. Java SWT类库概述2. SWT与AWT和Swing的区别2.1 历史背景与设计理念2.1.

使用SpringBoot整合Sharding Sphere实现数据脱敏的示例

《使用SpringBoot整合ShardingSphere实现数据脱敏的示例》ApacheShardingSphere数据脱敏模块,通过SQL拦截与改写实现敏感信息加密存储,解决手动处理繁琐及系统改... 目录痛点一:痛点二:脱敏配置Quick Start——Spring 显示配置:1.引入依赖2.创建脱敏