Spring 条件组件注解:`@Conditional` 与 `@ConditionalOnBean`

news/2024/11/8 18:49:38/

Spring 条件组件注解:@Conditional@ConditionalOnBean

文章目录

  • Spring 条件组件注解:`@Conditional` 与 `@ConditionalOnBean`
  • 一、`@Conditional` 基本使用
    • 0、条件组件是在非条件组件注册之后再进行注册的
    • 1、概述
    • 2、代码演示
    • 3、`@Conditional` 的优缺点
  • 二、Condition 接口的 `ConditionContext` 参数
    • 1、Condition 接口
    • 2、`ConditionContext` 参数
      • 源码
      • 方法简介
      • 使用示例
      • Condition实现需要遵循的规则
  • 三、`@ConditionalOnBean` 条件注解
    • 1、概述
      • 简介
      • 两个属性
    • 2、代码示例
      • 两个 Bean
      • 使用 `@ConditionalOnBean` 注解

一、@Conditional 基本使用

0、条件组件是在非条件组件注册之后再进行注册的

条件组件是在其他非条件组件注册之后注册的。

在Spring Framework中,条件组件通常会与非条件组件一起使用,以实现更复杂的配置。当一个条件组件被激活时,它会根据其定义的条件来决定是否加载其依赖的其他组件。

通常情况下,条件组件会在Spring容器启动时被注册,但它们并不会立即执行它们的逻辑。相反,当Spring容器检测到满足条件的情况时,条件组件才会被激活并执行它们的逻辑。这意味着如果一个条件组件依赖于另一个非条件组件,那么只有在满足条件时,后者才会被加载和执行。

因此,条件组件通常是在其他非条件组件之后注册的,并且只有在满足特定条件时才会被激活和执行。这种设计可以确保条件组件只在需要它们的时候才被加载和执行,从而提高应用程序的性能和效率。

1、概述

@Conditional注解用于根据某些条件来决定是否组件(比如Bean)是否生效。可用于:

  • @Bean

  • @Component

  • @Configuration

等来条件化这些组件的注册。

@Conditional 接受一个实现 Condition 接口的类作为参数。如果给定的条件计算结果为 true ,则相应的组件将被注册。

2、代码演示

定义一个 OnProd 条件来在生产环境中激活 Bean

public class OnProd implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return "prod".equals(context.getEnvironment().getProperty("env"));}
}

然后,可以在@Bean、@Configuration等上使用该条件

@Configuration
@Conditional(OnProd.class) 
public class ProdConfig {@Beanpublic Foo foo() { ... }
}

3、@Conditional 的优缺点

我们也可以定义更复杂的条件,检查网络接口、系统属性等等。所以,@Conditional注解为我们带来了如下好处:

  • 根据环境、属性等条件化地激活Bean;
  • 避免在不同环境中重复定义Bean;
  • 引入更高的灵活性和可扩展性;

但是,过度使用@Conditional也会带来一定的缺点:

  • 阅读和理解配置变得更加复杂
  • debugging变得更加困难;
  • 激活/不激活Bean的根本原因可能很难确定 ;

二、Condition 接口的 ConditionContext 参数

1、Condition 接口

用于注册组件必须匹配的单个条件。

在要注册bean定义之前立即检查条件,并可以根据此时可以确定的任何标准自由否决注册。

条件必须遵循与 BeanFactoryPostProcessor 相同的限制,并注意不要与bean实例交互。为了更细粒度地控制与 @ Configuration bean交互的条件,可以考虑实现 ConfigurationCondition 接口。

2、ConditionContext 参数

源码

package org.springframework.context.annotation;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.lang.Nullable;/*** Context information for use by {@link Condition} implementations.* 上下文信息,供 Condition 实现使用。** @author Phillip Webb* @author Juergen Hoeller* @since 4.0*/
public interface ConditionContext {BeanDefinitionRegistry getRegistry();@NullableConfigurableListableBeanFactory getBeanFactory();Environment getEnvironment();ResourceLoader getResourceLoader();@NullableClassLoader getClassLoader();}

方法简介

  • getBeanFactory():获取 BeanFactory ,可以检查其是否包含某个Bean
  • getEnvironment():获取 Environment ,可访问环境变量、应用程序参数等
  • getResourceLoader():获取 ResourceLoader ,可获取类路径资源
  • getClassLoader():获取 ClassLoader
  • getRegistry():获取Bean定义注册表,可检查是否注册了某个Bean

使用示例

该条件通过获取Environment并检查"db.type"属性来判断是否匹配。

public class MySQLCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Environment env = context.getEnvironment();return "MySQL".equals(env.getProperty("db.type")); }
}

检查是否注册了名为"foo"且类型为 Foo.class 的Bean。

public class FooExistsCondition implements Condition { @Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {BeanFactory bf = context.getBeanFactory();return bf.containsBean("foo") && bf.isTypeMatch("foo", Foo.class); } 
}

Condition实现需要遵循的规则

  • 不要在构造方法或matches方法中触发Bean定义的解析(会导致无限递归);
  • 缓存昂贵的操作结果(如类型匹配检查)以提高性能;
  • 尽量保持 matches 方法是幂等的(多次调用得到同样结果);

三、@ConditionalOnBean 条件注解

1、概述

简介

  • 仅在给定 Bean 存在的条件下,才会实例化配置类或Bean。

  • 可以实现依赖其他 Bean 的条件化配置。

当指定的 Bean 在 BeanFactory 中存在且类型匹配时,条件满足,相关的配置类或Bean会被实例化。

两个属性

  • value:指定需要检查的Bean名称(或名称数组)。

  • type:指定需要检查的Bean类型(或类型数组),不是必须的。

2、代码示例

两个 Bean

@Component
public class Foo { ... } @Component 
public class Bar { ... }

使用 @ConditionalOnBean 注解

  • FooConfig 会仅在名称为"foo"的Bean存在时被激活

  • BarConfig 会仅在类型为Bar的Bean存在时被激活

@Configuration
@ConditionalOnBean("foo") // 仅在foo Bean存在时激活
public class FooConfig { @Beanpublic Baz baz() { ... }
}@Configuration
@ConditionalOnBean(type = Bar.class) // 仅在Bar类型Bean存在时激活
public class BarConfig {@Beanpublic Qux qux() { ... }  
}

http://www.ppmy.cn/news/83225.html

相关文章

cpp 类成员函数delete this 会发生什么?

如题 this 简介: 每个非静态的类成员函数默认参数都会压栈一个this,它指向的是调用改成员函数的对象, 也是就className的object this 被隐含声明为 className* const this; 1.意味着不能改变this的指向2.this是个右值,不能取地址 ,不能&this 那我…

2023年NOC大赛创客智慧编程赛项Python 复赛模拟题(一)

题目来自:NOC大赛创客智慧编程赛项Python 复赛模拟题(一) 第一题: 编写一个彩票游戏:随机生成一个不重复的五位数作为彩票号,游戏提示用户输入一个五位整数,然后根据下面的规则判断用户是否能赢得奖金,最后要求输出彩票号和奖金。 (1)若用户输入的数字和彩票的数字完…

第十一章 枚举和注解

一、枚举 1. 介绍 (1)枚举:(enumeration,简写enum) (2)枚举是一组常量的集合 (3)枚举属于一种特殊的类,里面只包含一组有限的特定的对象 2. 枚举…

前端三剑客

一.前端是什么: 前端主要是考虑怎样能让用户觉得用起来更舒服,考虑界面布局、交互效果、页面加载速度等等,主要是偏向用户看得见的部分,客户端(pc、手机、pad)上浏览web。网站的“前端”是与用户直接交互的…

ES5 构造函数与ES6 Class的区别

Class 类中不存在变量提升 // es5var bar new Bar(); // 可行function Bar() {this.bar 42;}//es6const foo new Foo(); // Uncaught ReferenceErrorclass Foo {constructor() {this.foo 42;}} class内部会启用严格模式 // es5function Bar() {// 引用一个未声明的变量baz…

o3de 安装

工具依赖: Microsoft Visual Studio 2019 version 16.11.x. 或 Microsoft Visual Studio 2022 version 17.3.x.CMake 3.22.0 or later,建议3.26安装git安装 Git LFS,否则资源无法更新 下载源码: 建立根目录:o3de_dev/…

一次培训带来的思考

“有没有可能做的更好点”, 这是我从我的TL学到的最受益的一句。 背景 故事要从一次培训开始。话说要给部门做一次安全的培训,提升部门里所有人的安全意识。起初的设计是有讲解还有实操,所以最好在线下举行,人数限制而且时间较长…

【SpringBoot】k8s部署使用actuator做健康检查

环境介绍 开发依赖版本Spring Boot3.0.6JDK20 主要的pom依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <dependency><groupId>org.springframework…