Spring 4.2+:如何从@EventListener条件表达式中引用Spring bean实例

时间:2017-04-05 08:31:07

标签: java spring spring-el spring-bean

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

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

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

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

@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 matches T(my.package.RegExpEventHandler.MY_CONSTANT)

然后,我有一个示例事件监听器,它扩展了上面的Abstract类:

var resultStr = "[{\"Intent\":\"what is manufacturer name?\",\"Entity\":\"Name\",\"Response\":\"Test\",\"Status\":\"0\",\"Created_Date\":\"2017-04-04T00:00:00\",\"Response_Count\":0,\"Response_Count_string\":0},{\"Intent\":\"hi\",\"Entity\":\"hi\",\"Response\":\"hiiii\",\"Status\":\"0\",\"Created_Date\":\"2017-03-28T10:22:00\",\"Response_Count\":0,\"Response_Count_string\":0},{\"Intent\":\"how are you?\",\"Entity\":\"are you fine\",\"Response\":\"good!cool\",\"Status\":\"1\",\"Created_Date\":\"2017-03-28T10:22:38\",\"Response_Count\":0,\"Response_Count_string\":0}]";
   result = JSON.parse(resultStr);
       var data = result[0].Intent;

问题在于表达式

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

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

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

我知道我可以使用类似的东西轻松访问STATIC常量或方法:

{{1}}

但是无法使用@Value表达式从属性文件初始化 String constant (static final)。

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

提前多多感谢!

1 个答案:

答案 0 :(得分:3)

它对我有用 - 我查看了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)。