Spring注解解析:条件注解@Condition注解和@ConditonOnXXX注解

一、条件注解

条件注解的作用是给需要装载的Bean增加一个条件判断。只有满足条件才会装在到IoC容器中。而这个条件可以由自己去完成的,可以通过重写Condition接口重写matches()方法去实现自定义的逻辑。所以说这个注解增加了对Bean装载的灵活性。
在这里插入图片描述

  • @Conditonal:是一个元注解(meta-annotation),用于定义条件化的bean创建
  • @ConditionalOnBean:当指定的bean存在时,才会注册当前bean。
  • @ConditionalOnMissingBean:当指定的bean不存在时,才会注册当前bean。
  • @ConditionalOnClass:当指定的类在类路径上可用时,才会注册当前bean。
  • @ConditionalOnMissingClass:当指定的类在类路径上不可用时,才会注册当前bean。
  • @ConditionalOnProperty:当指定的属性具有指定的值时,才会注册当前bean。

二、@Conditional

1、使用方法

  • 自定义条件类
    需要实现org.springframework.context.annotation.Condition接口或继承org.springframework.context.annotation.Condition的某个实现类(如OnPropertyCondition、OnBeanCondition等)。 实现Condition接口需要覆盖matches(ConditionContext, AnnotatedTypeMetadata)方法,这个方法会返回一个布尔值,表示是否满足条件。
  • 在@Bean方法或@Configuration类上使用@Conditional
    可以将自定义的条件类作为@Conditional的值,或者直接使用Spring提供的条件注解(如@ConditionalOnProperty、@ConditionalOnBean等)。

2、示例

  • 服务是实现类
    我们需要定义两个Service接口的实现类,分别用于Windows和Linux操作系统。
// WindowsTomcatServiceImpl.java  
@Service  
public class WindowsTomcatServiceImpl implements TomcatService {  
    // Windows特定的实现  
}  
  
// LinuxTomcatServiceImpl.java  
@Service  
public class LinuxTomcatServiceImpl implements TomcatService {  
    // Linux特定的实现  
}
  • 自定义条件类
    我们需要创建两个条件类WindowsCondition和LinuxCondition,它们实现了Condition接口并检查当前操作系统。
// WindowsCondition.java  
public class WindowsCondition implements Condition {  
    @Override  
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {  
        return System.getProperty("os.name").toLowerCase().contains("windows");  
    }  
}  
  
// LinuxCondition.java  
public class LinuxCondition implements Condition {  
    @Override  
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {  
        return System.getProperty("os.name").toLowerCase().contains("linux");  
    }  
}
  • 在@Bean方法上使用@Conditional
    我们需要使用@Conditional注解来标记我们的配置类中的方法,以便根据操作系统类型来注入不同的Service实现。
// TomcatConfig.java  
@Configuration  
public class TomcatConfig {  
  
    @Bean  
    @Conditional(WindowsCondition.class)  
    public TomcatService windowsTomcatService() {  
        return new WindowsTomcatServiceImpl();  
    }  
  
    @Bean  
    @Conditional(LinuxCondition.class)  
    public TomcatService linuxTomcatService() {  
        return new LinuxTomcatServiceImpl();  
    }  
  
    // 如果需要,可以提供一个默认的实现,当没有满足条件的Bean时注入  
    @Bean  
    @ConditionalOnMissingBean(TomcatService.class)  
    public TomcatService defaultTomcatService() {  
        // 返回默认的实现或者抛出异常  
        throw new IllegalStateException("No supported TomcatService found for the current OS");  
    }  
}

TomcatConfig配置类根据当前操作系统的类型来注入不同的TomcatService实现。如果当前操作系统是Windows,则会注入WindowsTomcatServiceImpl;如果是Linux,则会注入LinuxTomcatServiceImpl。如果都没有匹配,那么会尝试注入defaultTomcatService,但由于它使用了@ConditionalOnMissingBean注解,并且总是返回一个异常,因此在实际应用中你可能需要提供一个真正的默认实现或者处理逻辑。

三、@ConditionalOnBean

1、介绍

Spring容器中是否存在对应的实例。可以通过实例的类型、类名、注解、昵称去容器中查找(可以配置从当前容器中查找或者父容器中查找或者两者一起查找)这些属性都是数组,通过"与"的关系进行查找。

@ConditionalOnBean 属性介绍

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnBeanCondition.class})
public @interface ConditionalOnBean {
    Class<?>[] value() default {};

    String[] type() default {};

    Class<? extends Annotation>[] annotation() default {};

    String[] name() default {};

    SearchStrategy search() default SearchStrategy.ALL;

    Class<?>[] parameterizedContainer() default {};
}
  • value:匹配的bean类型(例如:A.class)。
  • type:匹配的bean类型的类名(xxx.xxx.xxx.xxx.A)
  • name:匹配的bean的名字
  • search:搜索策略。提供CURRENT(只在当前容器中找)、PARENTS(只在所有的父容器中找;但是不包括当前容器)和ALL(CURRENT和PARENTS的组合)。

2、示例

假设你有一个接口MyService和两个实现类MyServiceImpl1和MyServiceImpl2。你还想要一个工厂类MyServiceFactory,它根据存在的实现类来返回相应的服务实例。

四、@ConditionalOnMissingBean

@ConditionalOnMissingBean 是 Spring Boot 中的一个条件注解。这个注解的主要用途是在 Spring 容器中注册 Bean 时进行条件判断。具体来说,当某个特定类型的 Bean 没有在容器中注册时,使用 @ConditionalOnMissingBean 注解的 Bean 才会被创建并注册。

源码如下:

package org.springframework.boot.autoconfigure.condition;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Conditional;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnBeanCondition.class})
public @interface ConditionalOnMissingBean {
    Class<?>[] value() default {};

    String[] type() default {};

    Class<?>[] ignored() default {};

    String[] ignoredType() default {};

    Class<? extends Annotation>[] annotation() default {};

    String[] name() default {};

    SearchStrategy search() default SearchStrategy.ALL;

    Class<?>[] parameterizedContainer() default {};
}

五、@ConditionalOnClass

@ConditionalOnClass 是 Spring Boot 中的一个条件注解,它的主要作用是根据类路径中是否包含指定的类来决定是否加载一个 Bean 或配置类。

源码如下:

package org.springframework.boot.autoconfigure.condition;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Conditional;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnClassCondition.class})
public @interface ConditionalOnClass {
    Class<?>[] value() default {};

    String[] name() default {};
}

六、@ConditionalOnMissingClass

@ConditionalOnMissingClass 是 Spring Boot 中的一个条件注解,它的主要作用是根据类路径中是否缺少指定的类来决定是否加载一个 Bean 或配置类。

具体来说,当类路径中不存在指定的类时,标注了 @ConditionalOnMissingClass 的配置类或 Bean 才会被加载;如果类路径中存在指定的类,则这些配置类或 Bean 会被忽略。

源码如下:

package org.springframework.boot.autoconfigure.condition;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Conditional;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnClassCondition.class})
public @interface ConditionalOnMissingClass {
    String[] value() default {};
}

七、@ConditionalOnProperty

@ConditionalOnProperty 是 Spring Boot 中的一个条件注解,它可以根据应用程序配置文件(如 application.properties 或 application.yml)中的属性值来决定是否启用某个组件或配置类。

源码:

package org.springframework.boot.autoconfigure.condition;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Conditional;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({OnPropertyCondition.class})
public @interface ConditionalOnProperty {
    String[] value() default {};

    String prefix() default "";

    String[] name() default {};

    String havingValue() default "";

    boolean matchIfMissing() default false;
}

  • value 和 name

    • 这两个属性都用于指定要检查的属性的名称。例如,@ConditionalOnProperty(value = “my.property”) 或 @ConditionalOnProperty(name = “my.property”) 都表示只有当 my.property 属性存在时才启用该组件或配置类。
    • value 和 name 可以互换使用,它们的作用相同。
  • prefix

  • 该属性用于指定要检查的属性的前缀。例如,@ConditionalOnProperty(prefix = “my”) 表示只有当以 my 为前缀的属性存在时才启用该组件或配置类。

  • 如果同时指定了 prefix 和 name 或 value,则它们会一起使用来检查完整的属性名。例如,@ConditionalOnProperty(prefix = “my”, name = “property”) 实际上会检查 my.property 这个属性。

  • havingValue

    • 该属性用于指定要检查的属性的值。只有当属性的值与该属性值匹配时,条件才成立。例如,@ConditionalOnProperty(name = “my.property”, havingValue = “true”) 表示只有当 my.property 的值为 true 时才启用该组件或配置类。
    • 如果不指定 havingValue,则只要属性存在(无论其值是什么)条件就成立。
  • matchIfMissing

    • 这是一个布尔属性,它决定了当指定属性不存在时,条件是否应该成立。默认值为 false,表示如果属性不存在,条件不成立。
    • 当你设置为 true 时,如果属性不存在,条件也会成立。这通常用于那些应该默认启用,但可以通过配置属性来禁用的组件或配置类。

参考

  • 官网:https://docs.spring.io/spring-boot/api/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.html
  • 源码:https://blog.csdn.net/qq_42697271/article/details/117155543?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1-117155543-blog-112269714.235v43pc_blog_bottom_relevance_base9&spm=1001.2101.3001.4242.2&utm_relevant_index=2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玉成226

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值