java - Spring 4.2+ : How to reference a Spring bean instance from inside an @EventListener condition expression

标签 java spring spring-el spring-bean

在 Spring 4.2+ 中,我们可以使用带有“条件”表达式的 @EventListener 注释。

在我的场景中,我需要将事件对象的 ID 与在 .properties 文件中配置的正则表达式相匹配。

但是,似乎不可能从条件的正则表达式中引用任何 bean 的属性或方法,因为根上下文似乎是事件对象本身。

到目前为止,我有一个抽象类,它根据类名设置事件 ID 模式属性。目标是使每个事件监听器的实现尽可能干净和简单。

@Service
@PropertySource(value = "classpath:subscriberEventMapping.properties")
public abstract class AbstractEventHandler implements IEventHandler {

    private String eventIdPattern;

    @Autowired
    Environment env;

    @Autowired(required = true)
    public void configureEventIdPattern() {
        String simpleClassName = this.getClass().getSimpleName();
        String resolvedEventIdPattern = env.getProperty(
            simpleClassName.substring(0,1).toLowerCase() + 
            simpleClassName.substring(1, simpleClassName.length()));
        this.eventIdPattern = resolvedEventIdPattern == null ? ".*" : resolvedEventIdPattern;
    }

    public String getEventIdPattern() {
        return eventIdPattern;
    }
}

属性文件如下所示:

regExpEventHandler=^(901|909|998|1000)$
dummyEventHandler=^([1-9][0-9]{0,2}|1000)$

然后,我有一个扩展上述抽象类的示例事件监听器:

@Service
public class RegExpEventHandler extends AbstractEventHandler {

    @Log
    private ILog logger;

    @Override
    @EventListener(condition = "#event.eventid matches @regExpEventHandler.getEventIdPattern()")
    public void onEvent(Event event) {
        logger.debug("RegExpEventHandler processing : {} with event pattern : {}", event, getEventIdPattern());
    }
}

问题是表达式

“#event.eventid 匹配@regExpEventHandler.getEventIdPattern()”

不起作用,因为在 @EventListener 使用的上下文中找不到 bean“@regExpEventHandler”。

这里有没有办法访问现有 Spring Bean 的方法或属性?对于这种情况还有其他更好的方法吗?

我知道我可以使用类似以下内容轻松访问 STATIC 常量或方法:

#event.eventid matches T(my.package.RegExpEventHandler.MY_CONSTANT)

但是字符串常量(static final)不能使用@Value 表达式从属性文件中初始化。

使用 NON-FINAL 静态常量可以工作,但是 EACH 事件监听器需要添加样板来使用非静态变量从非静态变量初始化静态常量@Value 表达式,这是我们要避免的。

提前致谢!

最佳答案

它对我有用 - 我查看了 EventExpressionEvaluator 并看到它向评估上下文添加了一个 bean 解析器...

public EvaluationContext createEvaluationContext(ApplicationEvent event, Class<?> targetClass,
        Method method, Object[] args, BeanFactory beanFactory) {

    Method targetMethod = getTargetMethod(targetClass, method);
    EventExpressionRootObject root = new EventExpressionRootObject(event, args);
    MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext(
            root, targetMethod, args, getParameterNameDiscoverer());
    if (beanFactory != null) {
        evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
    }
    return evaluationContext;
}

所以我写了一个快速测试...

@SpringBootApplication
public class So43225913Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(So43225913Application.class, args);
        context.publishEvent("foo");
    }

    @EventListener(condition = "@bar.accept(event)")
    public void listen(Object event) {
        System.out.println("handler:" + event);
    }

    @Bean
    public Bar bar() {
        return new Bar();
    }

    public static class Bar {

        public boolean accept(Object o) {
            System.out.println("bar:" + o);
            return true;
        }
    }

}

而且效果很好...

bar:org.springframework.context.PayloadApplicationEvent[...
handler:foo

(这是 4.3.7;引导 1.5.2)。

关于java - Spring 4.2+ : How to reference a Spring bean instance from inside an @EventListener condition expression,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43225913/

相关文章:

java - Java中队列的实现

spring - 使用常量解析属性时如何在 @Value 中使用 Spring-EL

java - XSLT 导入语句的 Saxon 错误

java - 字符串检查 while 循环无法正常工作

java - berkeley xml db作为java的嵌入式数据库

java - spring security 未调用 loadUserByUsername() 方法

java - 无法使用 Spring JPA READ UNCOMMITTED 隔离级别读取未提交的数据

eclipse - Spring项目的初始设置

spring - 使用 spring3 @Value 访问 PropertyPlaceholderConfigurer 值?

java - Spring 缓存 - 如何在 SPEL 中引用 bean 以通过 @Cacheable 启用条件缓存