自定义ConditionalOnXX注解(二)

一、前言

  在之前的文章《自定义ConditionalOnXX注解》中,介绍了Conditional注解的实现原理和实现自定义Conditional注解的基础方法,但是有些场景我们需要用一个ConditionalOnXX注解来实现多条件的与(AND)或(OR)非(NOT)逻辑,本文就是介绍这种复杂场景的应用。

二、自定义注解合并多条件

假设有一个bean MyBean,我们想通过当前操作系统标识来控制其是否注入到Spring容器中。

首先创建windows和mac系统的condition

OnWindowsCondition

/**
 * @author Ship
 * @version 1.0.0
 * @description:
 * @date 2023/01/31 10:20
 */
public class OnWindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return SystemUtils.IS_OS_WINDOWS;
    }
}

OnMacCondition

/**
 * @author Ship
 * @version 1.0.0
 * @description:
 * @date 2023/01/31 10:20
 */
public class OnMacCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return SystemUtils.IS_OS_MAC;
    }
}

2.1 与(AND)合并条件

SpringBoot提供了一个抽象类AllNestedConditions,具体用法其类注释写的比较清楚了如下:

/**
 * {@link Condition} that will match when all nested class conditions match. Can be used
 * to create composite conditions, for example:
 *
 * <pre class="code">
 * static class OnJndiAndProperty extends AllNestedConditions {
 *
 *    OnJndiAndProperty() {
 *        super(ConfigurationPhase.PARSE_CONFIGURATION);
 *    }
 *
 *    &#064;ConditionalOnJndi()
 *    static class OnJndi {
 *    }
 *
 *    &#064;ConditionalOnProperty("something")
 *    static class OnProperty {
 *    }
 *
 * }
 * </pre>
 * <p>
 * The
 * {@link org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase
 * ConfigurationPhase} should be specified according to the conditions that are defined.
 * In the example above, all conditions are static and can be evaluated early so
 * {@code PARSE_CONFIGURATION} is a right fit.
 *
 * @author Phillip Webb
 * @since 1.3.0
 */
public abstract class AllNestedConditions extends AbstractNestedCondition {
    
}

只需要新建一个condition类继承AllNestedConditions,重写构造方法并添加条件即可,需要注意的是构造方法里的ConfigurationPhase枚举分为两种情况,具体用哪个取决于Condition注解的使用场景。

ConfigurationPhase.PARSE_CONFIGURATION: 用于控制配置类是否生效

ConfigurationPhase.REGISTER_BEAN: 用于控制Bean是否加载

创建条件类OnWindowsAndMacCondition

package cn.sp.condition.nested;

import cn.sp.condition.OnMacCondition;
import cn.sp.condition.OnWindowsCondition;
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
import org.springframework.context.annotation.Conditional;

/**
 * @author Ship
 * @version 1.0.0
 * @description: 只有当所有条件都满足时,bean才会被加载
 * @date 2023/01/31 10:27
 */
public class OnWindowsAndMacCondition extends AllNestedConditions {

    public OnWindowsAndMacCondition() {
        super(ConfigurationPhase.REGISTER_BEAN);
    }

    @Conditional(OnWindowsCondition.class)
    static class OnWindows{

    }

    @Conditional(OnMacCondition.class)
    static class OnMac{

    }
}

自定义注解@ConditionalOnWindowsAndMac

/**
 * @author Ship
 * @version 1.0.0
 * @description: 条件之是windows且mac系统
 * @date 2023/01/31 10:19
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(value = OnWindowsAndMacCondition.class)
public @interface ConditionalOnWindowsAndMac {

}

2.2 或(OR)合并条件

创建条件类OnWindowsOrMacCondition

/**
 * @author Ship
 * @version 1.0.0
 * @description: 只要有一个条件满足时,bean就会被加载
 * @date 2023/01/31 10:27
 */
public class OnWindowsOrMacCondition extends AnyNestedCondition {

    public OnWindowsOrMacCondition() {
        super(ConfigurationPhase.REGISTER_BEAN);
    }

    @Conditional(OnWindowsCondition.class)
    static class OnWindows{

    }

    @Conditional(OnMacCondition.class)
    static class OnMac{

    }
}

自定义注解@ConditionalOnWindowsOrMac

/**
 * @author Ship
 * @version 1.0.0
 * @description: 条件之是windows或mac系统
 * @date 2023/01/31 10:19
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(value = OnWindowsOrMacCondition.class)
public @interface ConditionalOnWindowsOrMac {

}

2.3 非(NOT)合并条件

创建条件类OnNotWindowsCondition

/**
 * @author Ship
 * @version 1.0.0
 * @description: 只有当所有条件都不满足时,bean才会被加载
 * @date 2023/01/31 10:27
 */
public class OnNotWindowsCondition extends NoneNestedConditions {

    public OnNotWindowsCondition() {
        super(ConfigurationPhase.REGISTER_BEAN);
    }

    @Conditional(OnWindowsCondition.class)
    static class OnWindows {

    }
}

自定义注解@ConditionalOnNotWindows

/**
 * @author Ship
 * @version 1.0.0
 * @description: 条件之不是windows系统
 * @date 2023/01/31 10:19
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(value = OnNotWindowsCondition.class)
public @interface ConditionalOnNotWindows {

}

三、测试验证

TestConfiguration配置类添加了MyBean的注入方法

@Configuration
public class TestConfiguration {

   @ConditionalOnWindowsAndMac
//    @ConditionalOnWindowsOrMac
//    @ConditionalOnNotWindows
    @Bean
    public MyBean myBean() {
        System.out.println("Initialized bean:myBean...");
        return new MyBean();
    }
}

@ConditionalOnWindowsAndMac测试

本人机器是Mac系统,启动项目控制台没有任何输出,表明结果正常,毕竟没有既是windows又是mac的系统。

@ConditionalOnWindowsOrMac测试

将myBean()方法打上@ConditionalOnWindowsOrMac注解,启动项目控制台输出如下:

2023-01-31 20:51:25.584  INFO 16669 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 967 ms
Initialized bean:myBean...
2023-01-31 20:51:25.955  INFO 16669 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2023-01-31 20:51:25.965  INFO 16669 --- [           main] cn.sp.SpringExtensionApplication         : Started SpringExtensionApplication in 2.118 seconds (JVM running for 3.965)

说明MyBean被加载了,条件生效。

@ConditionalOnNotWindows测试

将myBean()方法打上@ConditionalOnNotWindows注解,启动项目控制台也打印出了[Initialized bean:myBean...],说明MyBean被加载了,条件生效。

文章代码已上传至github,点击查看

posted @ 2023-01-31 21:06  烟味i  阅读(102)  评论(0编辑  收藏  举报