Spring 条件注入注解 @Conditional

igxiaoshan Lv5

@Conditional注解详解

入门介绍

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
===================== 源码 ====================

package org.springframework.context.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;

/**
*
* @author Phillip Webb
* @author Sam Brannen
* @since 4.0
* @see Condition
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

/**
* All {@link Condition} classes that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();

}

@Conditional注解是从Spring 4.0版本引入;来源于spring-context包下;

@Conditional中文是条件的意思,它的作用是按照一定条件进行判断,满足条件给容器中注入Bean

注解说明

@Conditional只有一个参数,并且这个参数要求是继承Condition类,而且参数是个数组,可以传多个值.

@Condition类是一个函数式接口(只有一个方法的接口被称为函数式接口).matches方法就是比较方法,如果为true则注入,反之,如果为false则不注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
==================== 源码 ===================
/**
*
* @author Phillip Webb
* @since 4.0
* @see ConfigurationCondition
* @see Conditional
* @see ConditionContext
*/
@FunctionalInterface
public interface Condition {

/**
* Determine if the condition matches.
* @param context the condition context
* @param metadata the metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
* or {@link org.springframework.core.type.MethodMetadata method} being checked
* @return {@code true} if the condition matches and the component can be registered,
* or {@code false} to veto the annotated component's registration
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

@Conditional注解扩展

除了@Conditional注解外,springboot通过@Conditional注解扩展了很多注解;如

@ConditionalOnBean,@ConditionalOnClass,@ConditionalOnMissingBean ….

使用案例

自定义一个Condition实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @author : igsshan
* @date : 2023/11/21 15:33
* @since : 1.0
*/
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("condition.isOpen");
return Boolean.parseBoolean(property);
}
}

自定义一个实体类

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @author : igsshan
* @date : 2023/11/21 15:36
* @since : 1.0
*/
public class TestBeanUser {

@Override
public String toString() {
return "TestBeanUser .........";
}
}

编写配置类(注解使用在类上)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @author : igsshan
* @date : 2023/11/21 15:36
* @since : 1.0
*/
@Configuration
@Conditional(MyCondition.class)
public class ConditionConfig {

@Bean
public TestBeanUser user1() {
return new TestBeanUser();
}
}

编写配置文件

1
2
condition:
isOpen: true

编写启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @author : igsshan
* @date : 2023/11/21 14:23
* @since : 1.0
*/
@SpringBootApplication
public class ConditionalApplication {

public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(ConditionalApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
System.out.println("===================");
for (String beanName : beanDefinitionNames) {
System.out.println("beanName " + beanName);
}
System.out.println("===================");
boolean user1 = run.containsBean("user1");
System.out.println("容器中user1组件:" + user1);
boolean conditionConfig = run.containsBean("conditionConfig");
System.out.println("容器中conditionConfig组件:" + conditionConfig);
}
}

测试结果

1
2
3
===================
容器中user1组件:true
容器中conditionConfig组件:true

(注解使用在方法上)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @author : igsshan
* @date : 2023/11/21 15:36
* @since : 1.0
*/
@Configuration
public class ConditionConfig {

@Bean
@Conditional(MyCondition.class)
public TestBeanUser user1() {
return new TestBeanUser();
}
}

**运行结果 **

1
2
3
4
5
===================
容器中user1组件:true
容器中conditionConfig组件:true

// 同样可以满足条件使Bean定义信息注入到IOC容器中

@Conditional多条件

前面提到@Conditional注解可以接收一个Class数组,存在多条件类的情况

测试: 第一个Conditon实现类中matches方法返回false (只用于测试)

第二个Condition实现类

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @author : igsshan
* @date : 2023/11/21 15:51
* @since : 1.0
*/
public class ObstinateCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}

配置类改写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @author : igsshan
* @date : 2023/11/21 15:36
* @since : 1.0
*/
@Configuration
public class ConditionConfig {

@Bean
@Conditional({MyCondition.class, ObstinateCondition.class})
public TestBeanUser user1() {
return new TestBeanUser();
}
}

测试结果

1
2
3
===================
容器中user1组件:false
容器中conditionConfig组件:true

结论

1
2
当,多个条件中,其中任何一个条件为 false 则不注入
全部条件为 true 则注入

注解扩展

前面说到springboot官方对@Conditional注解有进行扩展

官方源码:

@ConditionalOnClass

该注解,主要是判断是否存在这个类文件,如果存在则表示满足条件,可以注入到容器当中

源码

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
/**
*
* @author Phillip Webb
* @since 1.0.0
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {

/**
* The classes that must be present. Since this annotation is parsed by loading class
* bytecode, it is safe to specify classes here that may ultimately not be on the
* classpath, only if this annotation is directly on the affected component and
* <b>not</b> if this annotation is used as a composed, meta-annotation. In order to
* use this annotation as a meta-annotation, only use the {@link #name} attribute.
* @return the classes that must be present
*/
Class<?>[] value() default {};

/**
* The classes names that must be present.
* @return the class names that must be present.
*/
String[] name() default {};

}

用法用例

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
/**
* @author : igsshan
* @date : 2023/11/21 15:36
* @since : 1.0
*/
@Configuration
public class ConditionConfig {

@Bean
@ConditionalOnClass(value = MyConfig.class)
public TestBeanUser user1() {
return new TestBeanUser();
}
}

// ==================== 或者 =========================
@Configuration
public class ConditionConfig {

@Bean
@ConditionalOnClass(name = "com.igsshan.springbootconditional.conifg.MyConfig")
public TestBeanUser user1() {
return new TestBeanUser();
}
}

// 注意: 使用 'name' 属性值,必须是全类名,方法名不能满足

@ConditionalOnMissingClass

@ConditionalOnMissingClass只有一个value属性.它和@ConditionalOnClass功能相反;

@ConditionalOnClassclass存在为true;

@ConditionalOnMissingClassclass不存在为true;true注入容器,false不注入容器

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
*
* @author Dave Syer
* @since 1.0.0
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnMissingClass {

/**
* The names of the classes that must not be present.
* @return the names of the classes that must not be present
*/
String[] value() default {};

}

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @author : igsshan
* @date : 2023/11/21 15:36
* @since : 1.0
*/
@Configuration
public class ConditionConfig {

@Bean
@ConditionalOnMissingClass(value = "com.igsshan.springbootconditional.conifg.MyConfig")
public TestBeanUser user1() {
return new TestBeanUser();
}
}

@ConditionalOnBean

Bean存在的时候注入,不存在的时候不注入

源码

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
*
* @author Phillip Webb
* @since 1.0.0
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {

/**
* The class types of beans that should be checked. The condition matches when beans
* of all classes specified are contained in the {@link BeanFactory}.
* @return the class types of beans to check
*/
Class<?>[] value() default {};

/**
* The class type names of beans that should be checked. The condition matches when
* beans of all classes specified are contained in the {@link BeanFactory}.
* @return the class type names of beans to check
*/
String[] type() default {};

/**
* The annotation type decorating a bean that should be checked. The condition matches
* when all of the annotations specified are defined on beans in the
* {@link BeanFactory}.
* @return the class-level annotation types to check
*/
Class<? extends Annotation>[] annotation() default {};

/**
* The names of beans to check. The condition matches when all of the bean names
* specified are contained in the {@link BeanFactory}.
* @return the names of beans to check
*/
String[] name() default {};

/**
* Strategy to decide if the application context hierarchy (parent contexts) should be
* considered.
* @return the search strategy
*/
SearchStrategy search() default SearchStrategy.ALL;

/**
* Additional classes that may contain the specified bean types within their generic
* parameters. For example, an annotation declaring {@code value=Name.class} and
* {@code parameterizedContainer=NameRegistration.class} would detect both
* {@code Name} and {@code NameRegistration<Name>}.
* @return the container types
* @since 2.1.0
*/
Class<?>[] parameterizedContainer() default {};

}

用法用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @author : igsshan
* @date : 2023/11/21 14:31
* @since : 1.0
*/
@Configuration
public class MyConfig {

@Bean(name = "tom")
public User1 userTom1() {
return new User1();
}

@Bean
@ConditionalOnBean(User1.class)
public User2 jerry() {
return new User2();
}
}

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @author : igsshan
* @date : 2023/11/21 14:23
* @since : 1.0
*/
@SpringBootApplication
public class ConditionalApplication {

public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(ConditionalApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
System.out.println("===================");
for (String beanName : beanDefinitionNames) {
System.out.println("beanName " + beanName);
}
System.out.println("===================");
boolean jerry = run.containsBean("jerry");
System.out.println("容器中jerry组件:" + jerry);
}
}

测试结果

1
2
3
beanName tom
===================
容器中jerry组件:true

测试结论

1
当,User1对象被注入到容器时,下面 User2也才会注入进去

配置类中Bean注入优先级问题

上面的测试,都是基于同一个配置类中的条件注入;

如果此时,我新创建一个MyConfigTest类,将原来MyConfig配置类中的User1bean信息转移到MyConfigTest配置类中

演示代码

  • MyConfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* @author : igsshan
* @date : 2023/11/21 14:31
* @since : 1.0
*/
@Configuration
public class MyConfig {

// 注释掉 bean定义
// @Bean
// public User1 userTom1() {
// return new User1();
// }

@Bean
@ConditionalOnBean(User1.class)
public User2 jerry() {
return new User2();
}
}
  • MyConfigTest
1
2
3
4
5
6
7
8
9
10
11
12
/**
* @author : igsshan
* @date : 2023/11/21 17:05
* @since : 1.0
*/
@Configuration
public class MyConfigTest {
@Bean
public User1 userTom1() {
return new User1();
}
}
  • 启动类不变
  • 测试结果
1
2
3
beanName userTom1
===================
容器中jerry组件:false
  • 引入疑问和解决方法
1
由于 Bean 加载的优先级不用,可能导致 User2 在需要注入判断条件的时候, User1 此时还没有成功注入;等到 User2 判断容器中没有该实例,为 false 不注入,之后; User1 才成功注入到容器中

解决方案1: 修改Bean加载的优先级

  • MyConfigTest中添加@Order提升加载的优先级
1
@Order(Ordered.HIGHEST_PRECEDENCE) //最高优先级
  • MyConfig中添加@Order降低加载的优先级
1
@Order(Ordered.LOWEST_PRECEDENCE) //最高优先级
  • 测试结果
1
2
3
beanName userTom1
===================
容器中jerry组件:false

发现: 通过修改Bean加载的优先级并不能避免这个问题;此方法不通

解决方案2: 控制配置类加载顺序

方案一测试结论可以发现: bean加载按照名称顺序加载的 (可以自行测试: 编写一个测试的配置类,让其名称顺序高于’MyConfig’类)

开发中却不太合适,每次刻意修改类名称来控制bean加载顺序

不过; springboot提供了方案

**@AutoConfigureBefore@AutoConfigureAfter**来控制配置类加载顺序

用法用例

  • MyConfigTest类上加上@AutoConfigureBefore(MyConfig.class)

    • 该注解的意思是: 在 MyConfig 实例化之前加载

    要让@AutoConfigureBefore生效,还需要在META-INF/spring.factories文件中添加配置

    1
    2
    3
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.igsshan.springbootconditional.conifg.MyConfigTest,\
    com.igsshan.springbootconditional.conifg.MyConfig
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @author : igsshan
* @date : 2023/11/21 17:05
* @since : 1.0
*/
@Configuration
@AutoConfigureBefore(MyConfig.class)
public class MyConfigTest {
@Bean
public User1 userTom1() {
return new User1();
}
}

META-INF/spring.factories文件

1
2
3
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.igsshan.springbootconditional.conifg.MyConfigTest,\
com.igsshan.springbootconditional.conifg.MyConfig

测试结果

1
2
3
beanName userTom1
===================
容器中jerry组件:false

成功解决 Bean 加载顺序的问题

@ConditionalOnMissingBean

Bean不存在的时候注入,存在的时候不注入;用法与@ConditionalOnBean相反

源码

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
*
* @author Phillip Webb
* @author Andy Wilkinson
* @since 1.0.0
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {

/**
* The class types of beans that should be checked. The condition matches when no bean
* of each class specified is contained in the {@link BeanFactory}.
* @return the class types of beans to check
*/
Class<?>[] value() default {};

/**
* The class type names of beans that should be checked. The condition matches when no
* bean of each class specified is contained in the {@link BeanFactory}.
* @return the class type names of beans to check
*/
String[] type() default {};

/**
* The class types of beans that should be ignored when identifying matching beans.
* @return the class types of beans to ignore
* @since 1.2.5
*/
Class<?>[] ignored() default {};

/**
* The class type names of beans that should be ignored when identifying matching
* beans.
* @return the class type names of beans to ignore
* @since 1.2.5
*/
String[] ignoredType() default {};

/**
* The annotation type decorating a bean that should be checked. The condition matches
* when each annotation specified is missing from all beans in the
* {@link BeanFactory}.
* @return the class-level annotation types to check
*/
Class<? extends Annotation>[] annotation() default {};

/**
* The names of beans to check. The condition matches when each bean name specified is
* missing in the {@link BeanFactory}.
* @return the names of beans to check
*/
String[] name() default {};

/**
* Strategy to decide if the application context hierarchy (parent contexts) should be
* considered.
* @return the search strategy
*/
SearchStrategy search() default SearchStrategy.ALL;

/**
* Additional classes that may contain the specified bean types within their generic
* parameters. For example, an annotation declaring {@code value=Name.class} and
* {@code parameterizedContainer=NameRegistration.class} would detect both
* {@code Name} and {@code NameRegistration<Name>}.
* @return the container types
* @since 2.1.0
*/
Class<?>[] parameterizedContainer() default {};

}

用法用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @author : igsshan
* @date : 2023/11/21 14:25
* @since : 1.0
*/
@Configuration
@ConditionalOnMissingBean(value = User.class)
public class ConditionalConfig {

@Bean(name = "user01")
public User1 user01() {
return new User1();
}
}

@ConditionalOnMissingBean表示,如果容器里面没有User的实例,就会向容器中注入一个User1的实例对象(不管注入的是什么对象,哪怕是原对象也可以)

注意:

@ConditionalOnMissingBean@ConditionalOnBean使用的时候,都可以不添加属性;当不添加任何属性的时候,就是判断当前注入的类型

@ConditionalOnMissingBean是判断当没有当前类型的时候进行注入

@ConditionalOnBean是判断如果有当前类型的则注入

用法用例

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
31
32
33
34
35
36
37
38
/**
* @author : igsshan
* @date : 2023/11/21 14:31
* @since : 1.0
*/
@Configuration
public class MyConfig {

@Bean(name = "tom")
public User tom() {
return new User();
}

@Bean
@ConditionalOnBean(User1.class)
public User2 jerry() {
return new User2();
}

@Bean(name = "user3")
@ConditionalOnBean
public User2 user3() {
return new User2();
}

@Bean(name = "user33")
@ConditionalOnMissingBean
public User3 user33() {
return new User3();
}

@Bean(name = "user4")
@ConditionalOnBean
public User4 user4() {
return new User4();
}
}

启动类

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
/**
* @author : igsshan
* @date : 2023/11/21 14:23
* @since : 1.0
*/
@SpringBootApplication
public class ConditionalApplication {

public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(ConditionalApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
System.out.println("===================");
for (String beanName : beanDefinitionNames) {
System.out.println("beanName " + beanName);
}
System.out.println("===================");
boolean jerry = run.containsBean("jerry");
System.out.println("容器中jerry组件:" + jerry);
System.out.println("===================");
boolean user3 = run.containsBean("user3");
System.out.println("容器中user3组件:" + user3);
System.out.println("===================");
boolean user33 = run.containsBean("user33");
System.out.println("容器中user33组件:" + user33);
System.out.println("===================");
boolean user4 = run.containsBean("user4");
System.out.println("容器中user4组件:" + user4);
}
}

测试结果

1
2
3
4
5
6
7
8
===================
容器中jerry组件:true
===================
容器中user3组件:true
===================
容器中user33组件:true
===================
容器中user4组件:false

@ConditionalOnProperty

@ConditionalOnProperty主要用于通过和springboot中的application配置文件搭配使用;通过配置来管理配置bean

源码

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
*
* @author Maciej Walkowiak
* @author Stephane Nicoll
* @author Phillip Webb
* @since 1.1.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {

/**
* Alias for {@link #name()}.
* @return the names
*/
String[] value() default {};

/**
* A prefix that should be applied to each property. The prefix automatically ends
* with a dot if not specified. A valid prefix is defined by one or more words
* separated with dots (e.g. {@code "acme.system.feature"}).
* @return the prefix
*/
String prefix() default "";

/**
* The name of the properties to test. If a prefix has been defined, it is applied to
* compute the full key of each property. For instance if the prefix is
* {@code app.config} and one value is {@code my-value}, the full key would be
* {@code app.config.my-value}
* <p>
* Use the dashed notation to specify each property, that is all lower case with a "-"
* to separate words (e.g. {@code my-long-property}).
* @return the names
*/
String[] name() default {};

/**
* The string representation of the expected value for the properties. If not
* specified, the property must <strong>not</strong> be equal to {@code false}.
* @return the expected value
*/
String havingValue() default "";

/**
* Specify if the condition should match if the property is not set. Defaults to
* {@code false}.
* @return if should match if the property is missing
*/
boolean matchIfMissing() default false;

}

源码属性值解析

**name **和 **value**用法一样

1
2
3
4
5
6
7
@ConditionalOnProperty(value = "timer.enabled")
或者
@ConditionalOnProperty(name = "timer.enabled")
// 值得说明:
// 1. name属性和value属性,不能同时使用,否则会报错
// 2. 只要配置的值是非false的值都有效
// 比如: timer.enabled=null 或者 timer.enabled=222 等都有效

profix

1
2
@ConditionalOnProperty(prefix = "timer", name = "enabled")
// 作用是把 name 直接命名为: timer.enabled 一样, prefix 可以和 name 或者 value 属性组合使用

havingValue

1
2
3
@ConditionalOnProperty(prefix = "timer", name = "enabled",havingValue = "open")
// havingValue 属性,只有当 name 或者 value 属性的值与 havingValue 属性完全相同时,注入有效
// 比如: timer.enabled=open

matchIfMissing

1
2
3
4
5
6
7
@ConditionalOnProperty(prefix = "timer", name = "enabled",havingValue = "open",matchIfMissing = true)
// matchIfMissing 属性;如果该属性为 true ;表示 name 或者 value 没有配置对应的属性也能注入;
// 默认 matchIfMissing 属性值为 false
// 注解配置示例
timer.enabled=null // 无效
timer.enabled=open // 有效
(不配置) // 有效

name 或者 **value**存在多个值的情况

1
2
3
4
5
6
7
8
9
10
11
12
@ConditionalOnProperty(prefix = "timer", name = {"enabled","isopen"},havingValue = "open")

// 这种情况要求 name 两个值都必须有且必须为 open 才有效
timer.enabled=open // 只有一个无效

timer.enabled=open
timer.isopen=open // 有效

timer.enabled=open
timer.isopen=111 // 无效

(不配置) // 无效

如果加上 matchIfMissing 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ConditionalOnProperty(prefix = "timer", name = {"enabled","isopen"},havingValue = "open",matchIfMissing = true)

// 表示可以缺少
不配置 // 有效

timer.enabled=open // 有效

timer.enabled=open
timer.isopen=open // 有效

timer.enabled=open
timer.isopen=111 // 无效

timer.enabled=111 // 无效

用法用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @author : igsshan
* @date : 2023/11/21 18:31
* @since : 1.0
*/
@Configuration
@ConditionalOnProperty(prefix = "condition.user", name = {"open"}, havingValue = "true")
public class MyPropertyConfig {

@Bean(name = "user5")
public User5 user5() {
return new User5();
}
}

配置文件

1
2
3
condition:
user:
open: true

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @author : igsshan
* @date : 2023/11/21 14:23
* @since : 1.0
*/
@SpringBootApplication
public class ConditionalApplication {

public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(ConditionalApplication.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
System.out.println("===================");
boolean user5 = run.containsBean("user5");
System.out.println("容器中user5组件:" + user5);
}
}

测试结果

1
2
3
beanName user5
===================
容器中user5组件:true

其他注解

  • @ConditionOnJava: 运行指定的Java版本才会加载 Bean
  • @ConditionOnWebApplication@ConditionOnNotWebApplication: 运行在(不在)web应用中才会加载这个Bean
  • @ConditionOnCloudPlatform: 运行在指定的云平台上才会加载指定的 Bean
  • @ConditionOnJndi: 指定的资源通过JNDI加载后才加载 Bean
  • @ConditionOnSingleCandidate(UserService.class): 表示容器中只有一个UserService类型的Bean才生效
  • @ConditionOnResource: 指定的静态资源文件存在才会加载指定的Bean
  • @ConditionOnExpression("${test.express} == true "): 通过spring提供的spEL表达式灵活配置,方表达式为true的时候,才会加载指定的Bean