zoukankan      html  css  js  c++  java
  • 聊聊 Spring Boot 中的 @Conditional 注解

    阅读 SpringBoot 自动配置源码的时候,可以看到很多以 @Conditional 开头的注解,

    这类注解的作用是根据条件决定是否注册 bean。本文对不同的条件做个归纳总结。

    了解 @Conditional

    @Conditional 注解是 Spring 4.0 中新增核心注解,作用是提供自动装配的条件约束,一般与 @Configuration 和 @Bean 配合使用。简单说,Spring 在解析 @Configuration 配置类的时候,如果该配置类增加了 @Conditional 注解,那么会根据该注解配置的条件来决定是否要实现 Bean 的装配。

    @Conditonal 注解类声明代码如下,该注解可以接收一个Condition 的数组,位于 org.springframework.context.annotation 包下。

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface Conditional {
    	Class<? extends Condition>[] value();
    }
    

    Condition 是一个函数式接口,提供了 matches 方法,它主要是提供一个条件匹配规则,返回 true 表示可以注入 Bean,反之不注入。

    package org.springframework.context.annotation;
    
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    @FunctionalInterface
    public interface Condition {
        boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
    }
    

    条件装配案例

    下面基于 @Conditional 实现一个条件装配案例。

    自定义一个 Condition ,如果当前操作系统是 Linux 就注册 linux,如果当前操作系统是 Mac OS X 就注册 mac。

    • 首先创建两个空类:
    public class Linux {}
    
    public class MacOSX {}
    
    • 创建 Condition :分别匹配两种操作系统
    package cn.itzhouq.starter.test.config;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class LinuxCondition implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            // 获取系统环境的属性
            String systemName = conditionContext.getEnvironment().getProperty("os.name");
            if (systemName.contains("Linux")) {
                return true;
            }
            return false;
        }
    }
    
    package cn.itzhouq.starter.test.config;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class MacOSXCondition implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            String systemName = conditionContext.getEnvironment().getProperty("os.name");
            if (systemName.contains("Mac OS X")) {
                return true;
            }
            return false;
        }
    }
    
    • 配置类
    package cn.itzhouq.starter.test.config;
    
    import cn.itzhouq.starter.test.pojo.Linux;
    import cn.itzhouq.starter.test.pojo.MacOSX;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class AppConfig {
    
        @Conditional(LinuxCondition.class)
        @Bean
        public Linux linux() {
            return new Linux();
        }
    
        @Conditional(MacOSXCondition.class)
        @Bean
        public MacOSX mac() {
            return new MacOSX();
        }
    }
    
    • 测试类
    package cn.itzhouq.starter.test;
    
    import cn.itzhouq.starter.test.config.AppConfig;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    /**
     * @author zhouquan
     * @date 2020/10/7 15:31
     */
    public class ConditionTest {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            String[] names = context.getBeanDefinitionNames();
            for (String name : names) {
                System.out.println("name = " + name);
            }
        }
    }
    
    • 结果:
    name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    name = org.springframework.context.annotation.internalCommonAnnotationProcessor
    name = org.springframework.context.event.internalEventListenerProcessor
    name = org.springframework.context.event.internalEventListenerFactory
    name = appConfig
    name = mac
    

    上面是我在 Mac 上运行程序的结果。如果修改参数:

    运行结果会显示 linux。

    Spring Boot 中的 @Conditional

    通过上面的案例可以明白 @Conditional 是如何帮助实现 Bean 的条件注入的。在 Spring Boot 中,针对该注解做了扩展,提供了更简单的使用形式。扩展的注解主要有以下这些:

    • ConditionalOnBean/ConditionalOnMissingBean:容器中存在某个 Bean 或者不存在某个 Bean 时进行装载。
    • ConditionalOnClass/ConditionalOnMissingClass:classpath 下存在指定的类或者不存在指定的类时进行装载。
    • ConditionalOnCloudPlatform:只有运行在指定的云平台上才加载指定的 Bean。
    • ConditionalOnExpression:基于 SpEl 表达式的条件判断。
    • ConditionalOnJava:只有运行指定版本的 Java 才加载 Bean。
    • ConditionalOnJndi:只有指定资源通过 JNDI 加载后才加载 Bean。
    • ConditionalOnWebApplication/ConditionalOnNotWebApplication:如果是 Web 应用或者不是 Web 应用,才加载指定的 Bean。
    • ConditionalOnProperty:系统中指定的属性是否有对应的值。
    • ConditionalOnResource:要加载的 Bean 依赖指定新资源是否存在于 classpath 中。
    • ConditionalOnSingleCandidate:只有在确定了给定 Bean 类的单个选项时才会加载 Bean。

    这些注解只需要添加到 @Configuration 配置类的类级别或者方法级别,然后根据每个注解的作用传参就行。

  • 相关阅读:
    GitHub 更新fork的代码
    robotframework出现错误:Keyword 'AppiumLibrary.Open Application' expected 1 to 2 non-keyword arguments,got 5.
    adb命令积累
    appium测试android环境搭建(win7)
    小明的自留地
    转载:appium踩过的坑
    junit3和junit4的使用区别如下
    Python线程指南
    实现ie低版本支持input type="number"
    LODOP打印开发
  • 原文地址:https://www.cnblogs.com/itzhouq/p/conditional.html
Copyright © 2011-2022 走看看