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

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

在Spring 4.2+中,我们可以使用带有"condition"表达式的@EventListener注解。

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

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

到目前为止,我有一个摘要 class,它根据 class 名称设置事件 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)$

然后,我有一个扩展上述摘要的示例事件监听器 class:

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

但是字符串常量(静态最终)无法使用@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)。