Spring的@ConditionalOnBean和@ConditionalOnClass与ConditionalOnExpression的使用

使用条件注解@ConditionalOnBean@ConditionalOnClass

本文将主要介绍根据配置来决定是否创建bean的注解@ConditionalOnProperty

I. 配置属性作为条件

主要是根据配置参数,来决定是否需要创建这个bean,这样就给了我们一个根据配置来控制Bean的选择的手段了,如前面一篇博文中根据配置来选择是随机生成boolean还是随机生成int;只需要更改配置即可

1. @ConditionalOnProperty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
true/**
	 * Alias for {@link #name()}.
	 * @return the names
	 */
trueString[] value() default {};

true// 配置前缀
trueString prefix() default "";

  // 配置名
trueString[] name() default {};

true// 要求配置存在,且包含某个值
trueString havingValue() default "";

true// 即便没有配置,也依然创建
trueboolean matchIfMissing() default false;
}

2. 实例测试

a. 测试用例

测试几个常用的姿势,一是根据配置是否存在,来决定是否创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class PropertyExistBean {
    private String name;

    public PropertyExistBean(String name) {
        this.name = name;
    }

    public String getName() {
        return "property : " + name;
    }
}

public class PropertyNotExistBean {
    private String name;

    public PropertyNotExistBean(String name) {
        this.name = name;
    }

    public String getName() {
        return "no property" + name;
    }
}

对应的bean配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * 配置存在时才会加载这个bean
 *
 * @return
 */
@Bean
@ConditionalOnProperty("conditional.property")
public PropertyExistBean propertyExistBean() {
    return new PropertyExistBean(environment.getProperty("conditional.property"));
}

/**
 * 即便配置不存在时,也可以加载这个bean
 *
 * @return
 */
@Bean
@ConditionalOnProperty(name = "conditional.property.no", matchIfMissing = true)
public PropertyNotExistBean propertyNotExistBean() {

 


return new PropertyNotExistBean("conditional.property");
}

当配置存在,且value匹配时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class PropertyValueExistBean {
    public String name;

    public PropertyValueExistBean(String name) {
        this.name = name;
    }

    public String getName() {
        return "property value exist: " + name;
    }
}

public class PropertyValueNotExistBean {
    public String name;

    public PropertyValueNotExistBean(String name) {
        this.name = name;
    }

    public String getName() {
        return "property value not exist: " + name;
    }
}

对应的配置如下

1
2
3
4
5
6
7
8
9
10
11
@Bean
@ConditionalOnProperty(name = {"conditional.property"}, havingValue = "properExists")
public PropertyValueExistBean propertyValueExistBean() {
    return new PropertyValueExistBean("properExists");
}

@Bean
@ConditionalOnProperty(name = {"conditional.property"}, havingValue = "properNotExists")
public PropertyValueNotExistBean propertyValueNotExistBean() {

 


return new PropertyValueNotExistBean("properNotExists");
}

接下来就是配置的参数

1
conditional.property=properExists

b. 实例演示

根据前面的分析,上面的四个bean中,PropertyExistBeanPropertyNotExistBeanPropertyValueExistBean 应该存在;而PropertyValueNotExistBean 因为配置值不匹配,不会创建

测试代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@RestController
@RequestMapping(path = "property")
public class PropertyRest {

    @Autowired(required = false)
    private PropertyExistBean propertyExistBean;
    @Autowired(required = false)
    private PropertyNotExistBean propertyNotExistBean;
    @Autowired(required = false)
    private PropertyValueExistBean propertyValueExistBean;
    @Autowired(required = false)
    private PropertyValueNotExistBean propertyValueNotExistBean;

    @GetMapping(path = "show")
    public String show() {
        Map<String, String> result = new HashMap<>(4);
        // 存在
        result.put("propertyExistBean", propertyExistBean == null ? "null ===> false" : propertyExistBean.getName());
        // 存在
        result.put("propertyNotExistBean",
                propertyNotExistBean == null ? "null ===> false" : propertyNotExistBean.getName());
        // 存在
        result.put("propertyValueExistBean",
                propertyValueExistBean == null ? "null ==> false" : propertyValueExistBean.getName());
        // 不存在
        result.put("propertyValueNotExistBean",
                propertyValueNotExistBean == null ? "null ==> true" : propertyValueNotExistBean.getName());
        return JSONObject.toJSONString(result);
    }
}

执行后结果如下,一如预期

Spring的@ConditionalOnBean和@ConditionalOnClass与ConditionalOnExpression的使用

基于SPEL表达式的条件注解ConditionalOnExpression

IV. 表达式条件注入

相比较前面的Bean,Class是否存在,配置参数是否存在或者有某个值而言,这个依赖SPEL表达式的,就显得更加的高级了;其主要就是执行Spel表达式,根据返回的true/false来判断是否满足条件

至于SPEL是什么东西,后面会有专文进行解释,此处不加以展开。下面以一个简单的demo进行演示它的使用姿势

1. @ConditionalOnExpression

接口定义

1
2
3
4
5
6
7
8
9
10
11
12
13
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnExpressionCondition.class)
public @interface ConditionalOnExpression {

true/**
true * The SpEL expression to evaluate. Expression should return {@code true} if the
true * condition passes or {@code false} if it fails.
true * @return the SpEL expression
true */
trueString value() default "true";
}

2. 实例测试

用一个简单的例子,当配置参数中,根据是否满足某个条件来决定是否需要加载bean

a. 测试用例

定义一个满足条件和一个不满足的bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ExpressFalseBean {
    private String name;

    public ExpressFalseBean(String name) {
        this.name = name;
    }

    public String getName() {
        return "express bean :" + name;
    }
}

public class ExpressTrueBean {
    private String name;

    public ExpressTrueBean(String name) {
        this.name = name;
    }

    public String getName() {
        return "express bean :" + name;
    }
}

重点关注下bean的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
public class ExpressAutoConfig {
    /**
     * 当存在配置,且配置为true时才创建这个bean
     * @return
     */
    @Bean
    @ConditionalOnExpression("#{'true'.equals(environment['conditional.express'])}")
    public ExpressTrueBean expressTrueBean() {
        return new ExpressTrueBean("express true");
    }

    /**
     * 配置不存在,或配置的值不是true时,才创建bean
     * @return
     */
    @Bean
    @ConditionalOnExpression("#{!'true'.equals(environment.getProperty('conditional.express'))}")
    public ExpressFalseBean expressFalseBean() {
        return new ExpressFalseBean("express != true");
    }
}

对应的配置如下

1
conditional.express=true

b. 实例演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
@RequestMapping(path = "express")
public class ExpressRest {
    @Autowired(required = false)
    private ExpressTrueBean expressTrueBean;
    @Autowired(required = false)
    private ExpressFalseBean expressFalseBean;

    @GetMapping(path = "show")
    public String show() {
        Map<String, String> result = new HashMap<>(4);
        result.put("expressTrueBean", expressTrueBean == null ? "null ==> false" : expressTrueBean.getName());
        result.put("expressFalseBean", expressFalseBean == null ? "null ==> true": expressFalseBean.getName());
        return JSONObject.toJSONString(result);
    }
}

上面的执行,expressTrueBean应该存在,另外一个为null,运行结果如下

Spring的@ConditionalOnBean和@ConditionalOnClass与ConditionalOnExpression的使用

 

上一篇:简单读!tomcat源码(一)启动与监听


下一篇:@ConditionalOnBean、@ConditionalOnMissingBean