首页 > 其他分享 >spring框架 - 通过 @Conditional注解来条件化地应用注解

spring框架 - 通过 @Conditional注解来条件化地应用注解

时间:2024-01-28 11:45:48浏览次数:19  
标签:String spring Conditional annotationName 注解 true class

条件化地应用注解

什么意思呢? 参考chatGPT的回答:
Spring 框架允许您通过 @Conditional 注解来条件化地应用注解。@Conditional 注解用于在特定条件下决定是否应用某个注解或配置。这在很多情况下是非常有用的,特别是在需要根据应用的运行时环境或配置来动态地选择性地应用某些注解时。

下面是一个示例,展示了如何使用 @Conditional 注解:

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.type.AnnotatedTypeMetadata;

import java.util.Map;

public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 这里可以根据特定条件来确定是否应用注解
        Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalAnnotation.class.getName());
        if (attributes != null) {
            // 在这里可以检查条件并返回相应的布尔值
            // 例如,可以从 Spring 的环境中获取属性,然后根据属性值决定是否匹配条件
            return true; // 或者根据条件返回 true 或 false
        }
        return false;
    }
}

@Conditional(MyCondition.class)
public @interface ConditionalAnnotation {
    // 这是一个标记注解,只有在 MyCondition 中的 matches 方法返回 true 时才会应用
}

在这个例子中,@ConditionalAnnotation 注解会根据 MyCondition 类中的条件来决定是否应用。MyCondition 类实现了 Condition 接口,其中的 matches() 方法用于定义特定的条件。根据实际需要,你可以在 matches() 方法中编写逻辑来确定是否应该应用该注解。

通过这种方式,你可以动态地根据应用的环境、配置或其他条件来控制哪些注解会生效。

即通过这种方式,我们可以通过配置文件来控制是否运用某一个注解。

实战

用过spring-boot-actuator的同学,可能知道,actuator可以把spring boot的指标数据发送到prometheus或者InfluxDB第三方存储服务。

可以通过配置文件来控制指标数据要发送到哪里。

management:
    metrics:
		export:
		  defaults:
			enabled: false
		  influx:
			enabled: true
		  prometheus:
			enabled: true

这段配置,告诉actuator,指标数据要发往influxDB,不发往prometheus。

那么,代码层面是如何控制发与不发呢?这里就涉及到“条件化应用注解”。

下面进行源码分析(基于spring boot 2.7):

@AutoConfiguration(
		before = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },
		after = MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class)
@ConditionalOnClass(InfluxMeterRegistry.class)
@ConditionalOnEnabledMetricsExport("influx")
@EnableConfigurationProperties(InfluxProperties.class)
public class InfluxMetricsExportAutoConfiguration {

}

这里的关键代码@ConditionalOnEnabledMetricsExport("influx")
当它返回false时,就不对InfluxMetricsExportAutoConfiguration这个bean进行自动配置。返回true时,就进行自动配置。

@ConditionalOnEnabledMetricsExport 的源码如下:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnMetricsExportEnabledCondition.class)
public @interface ConditionalOnEnabledMetricsExport {

	/**
	 * The name of the metrics exporter.
	 * @return the name of the metrics exporter
	 */
	String value();

}

@Conditional(OnMetricsExportEnabledCondition.class) 注解的核心代码如下:

@Override
	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
		AnnotationAttributes annotationAttributes = AnnotationAttributes
			.fromMap(metadata.getAnnotationAttributes(this.annotationType.getName()));
		String endpointName = annotationAttributes.getString("value");
		ConditionOutcome outcome = getEndpointOutcome(context, endpointName);
		if (outcome != null) {
			return outcome;
		}
		return getDefaultOutcome(context, annotationAttributes);
	}

先说结论:
先判断management.metrics.export.influx.enabled 是否是true。如果没有配置的话,就再去判断management.metrics.export.defaults.enabled是否为true

相关知识点:
1、AnnotatedTypeMetadata类:对注解元素的封装适配。

什么叫注解元素(AnnotatedElement)?比如我们常见的Class、Method、Constructor、Parameter等等都属于它的子类都属于注解元素。简单理解:只要能在上面标注注解都属于这种元素。Spring4.0新增的这个接口提供了对注解统一的、便捷的访问,使用起来更加的方便高效了。

// @since 4.0
public interface AnnotatedTypeMetadata {

	// 此元素是否标注有此注解~~~~
	// annotationName:注解全类名
	boolean isAnnotated(String annotationName);
	
	// 这个就厉害了:取得指定类型注解的所有的属性 - 值(k-v)
	// annotationName:注解全类名
	// classValuesAsString:若是true表示 Class用它的字符串的全类名来表示。这样可以避免Class被提前加载
	@Nullable
	Map<String, Object> getAnnotationAttributes(String annotationName);
	@Nullable
	Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString);

	// 参见这个方法的含义:AnnotatedElementUtils.getAllAnnotationAttributes
	@Nullable
	MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);
	@Nullable
	MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);
}

(1)通过AnnotatedTypeMetadata,获取可以注解的属性值。@ConditionalOnEnabledMetricsExport的属性值就是"influx"

标签:String,spring,Conditional,annotationName,注解,true,class
From: https://www.cnblogs.com/xushengbin/p/17992652

相关文章

  • springboot中@Repository 和 @Mapper的区别
    在springboot中他们两都是数据访问层的注解(在定义方面)@Repository:@Repository注解通常用于对DAO(DataAccessObject)组件进行标识。它告诉Spring框架,被注解的类是用于数据访问的组件,可以通过Spring的组件扫描机制自动注册为SpringBean,并且可以将底层的数据访问异......
  • SpringBoot日志配置
    1.简介Spring使用spring5及以后commons-logging被spring直接自己写了。支持log4j2,logback是默认使用的。虽然日志框架很多,但是我们不用担心,使用SpringBoot的默认配置就能工作的很好。 SpringBoot怎么把日志默认配置好的1、每个starter场景,都会导入一个核心场景......
  • 如何改Maven Dependencies的源码,如何把springboot组件的源码改造后使用
    由于springboot提供的源码有些地方不太符合预期,所以需要改动改动,这里就会说到,如何改MavenDependencies的源码。如何把springboot组件的源码改造后使用。v修改源码的几种方式直接在自己工程中建同包同类名的类进行替换采用@Primary注解排除需要替换的jar包中的类@Bean......
  • Springboot CRUD简单实现
    SpringBoot对Spring的改善和优化,它基于约定优于配置的思想,提供了大量的默认配置和实现使用SpringBoot之后,程序员只需按照它规定的方式去进行程序代码的开发即可,而无需再去编写一堆复杂的配置SpringBoot的主要功能如下:起步依赖:SpringBoot以功能化的方式将需要的依赖进行组装,并......
  • MyBatis注解模式和优化
    MyBatis注解模式之前我们使用xml文件方式实现sql语句的编写,我们也可以使用注解模式编写sql语句。前面的基本配置一致,不再叙述。第一步:创建实体类根据数据库的列名与表名设计实体类数据库信息:(表名t_student)实体类:@Data@NoArgsConstructor@AllArgsConstructorpubliccla......
  • SpringBoot启动过程中发布的事件
    springboot启动过程中会发布的事件(启动类的run()方法执行时)ApplicationStartingEvent:应用运行开始事件SpringBoot运行run()方法未进行任务操作时先发布此事件ApplicationEnvironmentPreparedEvent:Environment准备完成事件在Environement准备完成且应用上下文context......
  • 注解@CrossOrigin详解
    转载自:https://blog.csdn.net/MobiusStrip/article/details/84849418文章目录注解@CrossOrigin一、跨域(CORS)支持:二、使用方法:1、controller配置CORS1.1、controller方法的CORS配置1.2、为整个controller启用@CrossOrigin1.3、同时使用controller和方法级别的C......
  • SpringAOP
    一、AOP介绍AOP(面向切面编程)是一种编程思想,底层逻辑是动态代理。什么是动态代理呢?动态代理就是不改变源码的情况下,对目标方法进行增强。传统的动态代理太过繁琐,因此SpringAOP对其进行了一系列简化,使得原本繁琐的代码变得精简,同时使用也更加灵活。二、AOP使用案例在开发过程......
  • springboot学习:建立springboot项目及相关注意事项
    一、建立maven项目后引入依赖:以下没有版本号的依赖表示在springboot父依赖中已锁定相应的版本号必需依赖:1.springboot父依赖<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.5</versio......
  • SpringBoot启动项目报错:java.lang.UnsatisfiedLinkError: D:\files\software\jdk-1
    目录问题描述解决方法:问题描述在运行向的时候出现报错:java.lang.UnsatisfiedLinkError:D:\files\software\jdk-15.0.1\jdk-17.0.3.1\bin\tcnative-1.dll:Can'tloadIA32-bit.dllonaAMD64-bitplatform atjava.base/jdk.internal.loader.NativeLibraries.load(Native......