@Conditional
注解
这个注解在Spring4中引入,其主要作用就是判断条件是否满足,从而决定是否初始化并向容器注册Bean
1. 定义
@Conditional
注解定义如下,其内部主要就是利用了Condition接口,来判断是否满足条件,从而决定是否需要加载Bean
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional { Class<? extends Condition>[] value(); }
下面是Condtion
接口的定义,这个可以说是最基础的入口了,其他的所有条件注解,归根结底,都是通过实现这个接口进行扩展的
@FunctionalInterface public interface Condition { boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2); }
这个接口中,有个参数比较有意思ConditionContext
,它持有不少有用的对象,可以用来获取很多系统相关的信息,来丰富条件判断,接口定义如下
public interface ConditionContext { // 获取Bean定义 BeanDefinitionRegistry getRegistry(); // 获取Bean工程,因此就可以获取容器中的所有bean @Nullable ConfigurableListableBeanFactory getBeanFactory(); // environment 持有所有的配置信息 Environment getEnvironment(); // 资源信息 ResourceLoader getResourceLoader(); // 类加载信息 @Nullable ClassLoader getClassLoader(); }
2、如何使用Condition和@Conditional
注解,来实现bean的条件加载,自动扫描Bean的条件加载
从使用来讲,和前面的没有什么区别,只是将注解放在具体的类上而言,同样给出一个示例,先定义一个bean
@Component @Conditional(ScanDemoCondition.class) public class ScanDemoBean { @Value("${conditional.demo.load}") private boolean load; public boolean getLoad() { return load; } }
对应的判断条件如下,当配置文件中conditional.demo.load
为true时,才会加载这个配置,否则不实例化
public class ScanDemoCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { return "true".equalsIgnoreCase(conditionContext.getEnvironment().getProperty("conditional.demo.load")); } }
测试类和前面差不多,稍微注意下的就是自动注入时,改一下必要条件,避免bean不存在时报错
@Autowired(required = false) private ScanDemoBean scanDemoBean; @GetMapping(path = "/scan") public String showDemo() { String type = environment.getProperty("conditional.demo.load"); if (scanDemoBean == null) { return "not exists! >>>" + type; } else { return "load : " + scanDemoBean.getLoad() + " >>>" + type; } }
3、Spring框架提供了一系列相关的注解,如下表
注解 | 说明 |
---|---|
@ConditionalOnSingleCandidate |
当给定类型的bean存在并且指定为Primary的给定类型存在时,返回true |
@ConditionalOnMissingBean |
当给定的类型、类名、注解、昵称在beanFactory中不存在时返回true.各类型间是or的关系 |
@ConditionalOnBean |
与上面相反,要求bean存在 |
@ConditionalOnMissingClass |
当给定的类名在类路径上不存在时返回true,各类型间是and的关系 |
@ConditionalOnClass |
与上面相反,要求类存在 |
@ConditionalOnCloudPlatform |
当所配置的CloudPlatform为激活时返回true |
@ConditionalOnExpression |
spel表达式执行为true |
@ConditionalOnJava |
运行时的java版本号是否包含给定的版本号.如果包含,返回匹配,否则,返回不匹配 |
@ConditionalOnProperty |
要求配置属性匹配条件 |
@ConditionalOnJndi |
给定的jndi的Location 必须存在一个.否则,返回不匹配 |
@ConditionalOnNotWebApplication |
web环境不存在时 |
@ConditionalOnWebApplication |
web环境存在时 |
@ConditionalOnResource |
要求制定的资源存在 |
@ConditionalOnExpression |
? 当表达式为true的时候,才会实例化一个Bean。 |
@ConditionalOnProperty 注解
@Configuration public class WebConfig { @Bean @ConditionalOnProperty(prefix = "rest", name = "auth-open", havingValue = "true", matchIfMissing = true) public AuthFilter jwtAuthenticationTokenFilter() { return new AuthFilter(); } }
- prefix:application.properties配置的前缀
- name:属性是从application.properties配置文件中读取属性值
- havingValue:配置读取的属性值跟havingValue做比较,如果一样则返回true,否则返回false;如果返回值为false,则该configuration不生效;为true则生效
- matchIfMissing = true:表示如果没有在application.properties设置该属性,则默认为条件符合
上面代码的意思:是否启动jwt的的配置,如果application.properties配置中没有设置就启动jwt,如果设置了true就启动,如果false就关闭。
application.properties 配置如下
rest: auth-open: true # jwt鉴权机制是否开启(true或者false)