Spring专题「实战系列」针对Spring注解@ConditionalOnExpression详细使用说明

Posted 洛神灬殇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring专题「实战系列」针对Spring注解@ConditionalOnExpression详细使用说明相关的知识,希望对你有一定的参考价值。

前提介绍

通过Spring框架进行判断的Bean,Class是否存在,配置参数是否存在或者有某个值而言,这个依赖SPEL表达式的,就显得更加的高级了;其主要就是执行Spel表达式,根据返回的true/false来判断是否满足条件。至于SPEL是什么东西,下面以一个简单的demo进行演示它的使用姿势。

@ConditionalOnExpression

接口定义

@Retention(RetentionPolicy.RUNTIME)
@Target( ElementType.TYPE, ElementType.METHOD )
@Documented
@Conditional(OnExpressionCondition.class)
public @interface ConditionalOnExpression 

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

实例测试

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

测试用例

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

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;
    

采用#的方式进行分析配置

采用#通过environment的对象进行获取相关的配置信息key

@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");
    

对应的配置如下

conditional.express=true

实例演示

@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);
    

采用$的方式进行分析配置

@ConditionalOnExpression("$mq.consumer.enabled==1&&$rabbitmq.comsumer.enabled:true")
@ConditionalOnExpression("'$mq.consumer'.equals('rabbitmq')")

解析配置类

使用@ConditionalOnExpression(“‘$task.enable’.equals(‘true’)”)这种方式的话,是可以的。由于这个配置在自定义的文件中,因此使用了

@PropertySource(value= "classpath:taskconfig.yml", ignoreResourceNotFound = true , factory = MixPropertySourceFactory.class) 引入配置文件。 MixPropertySourceFactory是自定义的类,用于加载yml类型的配置文件。

public class MixPropertySourceFactory extends DefaultPropertySourceFactory 

  @Override

  public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException 
    String sourceName = name != null ? name : resource.getResource().getFilename();
    if (!resource.getResource().exists()) 
      return new PropertiesPropertySource(sourceName, new Properties());
     else if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) 
      Properties propertiesFromYaml = loadYml(resource);
      return new PropertiesPropertySource(sourceName, propertiesFromYaml);
     else 
      return super.createPropertySource(name, resource);
    
  

  private Properties loadYml(EncodedResource resource) throws IOException 
    YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
    factory.setResources(resource.getResource());
    factory.afterPropertiesSet();
    return factory.getObject();
  

在application.properties

写如下配置就不会是实例化这个bean

database.isEmbedded:true
@Bean
@ConditionalOnExpression("!$database.isEmbedded:true")
public ConnectionPool dataSourceMBean(DataSourceProxy dataSourceProxy) throws SQLException 
    return dataSourceProxy.createPool().getJmxPool();

Condition注解使用

Spring提供了很多Condition给我们用,@ConditionalOnExpression表示基于SpEL表达式作为判断条件,这个组合了@Conditional元注解,只是使用了不同的条件(Conditional)

@Conditional,满足特定条件创建一个Bean,SpringBoot就是利用这个特性进行自动配置的。

首先,两个Condition,判断当前系统是否是Windows或者Linux(True False)

public class LinuxCondition implements Condition 
    @Override
    public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) 
        return arg0.getEnvironment().getProperty("os.name").contains("Linux");
    

public class WindowsCondition implements Condition 
    @Override
    public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) 
        return arg0.getEnvironment().getProperty("os.name").contains("Windows");
    

然后,2个ListService实现类,表明不同系统下的ListService实现。

public interface ListService 
    public String showListCmd();

public class LinuxListService implements ListService
    @Override
    public String showListCmd() 
        return "ls";
        

public class WindowsListService implements ListService
    @Override
    public String showListCmd() 
        return "dir";
        

然后ConditionConfig使用了Java配置与@Conditional注解,根据LinuxCondition,或者WindowsCondition作为判断条件

@Configuration
public class ConditionConfig 

    @Bean
    @Conditional(WindowsCondition.class)
    public ListService windowsListService() 
        return new WindowsListService();
    

    @Bean
    @Conditional(LinuxCondition.class)
    public ListService linuxListService() 
        return new LinuxListService();
    

最后,App.java 测试成功。

public class App 
    public static void main(String[] args) 

        ApplicationContext context = new AnnotationConfigApplicationContext(
                ConditionConfig.class);

        ListService ls = context.getBean(ListService.class);
        System.out.println(context.getEnvironment().getProperty("os.name")
                + "系统下的列表命令为:" + ls.showListCmd());
    

参考资料

以上是关于Spring专题「实战系列」针对Spring注解@ConditionalOnExpression详细使用说明的主要内容,如果未能解决你的问题,请参考以下文章

#私藏项目实操分享#Spring专题「实战系列」spring注解@ConditionalOnExpression详细使用说明

#yyds干货盘点#Spring专题「实战系列」Spring Security原理以及实战认证分析开发指南

深入浅出Spring原理及实战「开发实战系列」Spring-Cache扩展自定义(注解失效时间+主动刷新缓存)

深入浅出Spring原理及实战「开发实战系列」SpringSecurity技术实战之通过注解表达式控制方法权限

Spring实战Spring注解配置工作原理源码解析

小伙伴们在催更Spring系列,于是我写下了这篇注解汇总!!