You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring @EventListener条件省略枚举全限定名引发SpEL解析异常

解决Spring @EventListener中SpEL解析异常并省略枚举全限定名的问题

问题背景

环境:Spring、Java 8

定义枚举类:

public enum NEStatus {
    Online(0), 
    Offline(1),
    Unknown(2);
}

原本使用枚举全限定名的@EventListener代码可正常运行:

@EventListener(condition = "#sdnStatusEvent.getNeStatus() != null && #sdnStatusEvent.getNeStatus() == T(com.mycompany.myproject.NEStatus).Offline")
public void handleSdnStatusEvent(SdnStatusEvent sdnStatusEvent) {
    LOGGER.info("handleSdnStatusEvent: sdnStatusEvent = {}", sdnStatusEvent);
}

修改为省略全限定名的写法后触发SpEL解析异常:

@EventListener(condition = "#sdnStatusEvent.getNeStatus() != null && #sdnStatusEvent.getNeStatus() == #object.NEStatus.name() == 'Offline'")
public void handleSdnStatusEvent(SdnStatusEvent sdnStatusEvent) {
    LOGGER.info("handleSdnStatusEvent: sdnStatusEvent = {}", sdnStatusEvent);
}

异常信息:

2023-07-05 12:25:34.424 ERROR [ContextLoader:localhost-startStop-1] Context initialization failed
org.springframework.expression.spel.SpelParseException: EL1041E: After parsing a valid expression, there is still more data in the expression: 'eq(==)'
        at org.springframework.expression.spel.standard.InternalSpelExpressionParser.doParseExpression(InternalSpelExpressionParser.java:129) ~[spring-expression-4.3.22.RELEASE.jar:4.3.22.RELEASE]

错误原因

修改后的SpEL表达式存在两个核心问题:

  1. SpEL不支持链式相等判断(连续使用==),这是触发解析异常的直接原因。
  2. #object.NEStatus的写法不符合SpEL语法,#object在@EventListener的condition上下文里并非指向枚举类实例。

解决方法

方法1:直接调用枚举实例的name()方法比较字符串

这是最简洁的方案:利用枚举类自带的name()方法获取常量名称,直接与目标字符串比较,无需枚举全限定名,同时语法完全符合SpEL规范。

修改后的代码:

@EventListener(condition = "#sdnStatusEvent.getNeStatus() != null && #sdnStatusEvent.getNeStatus().name() == 'Offline'")
public void handleSdnStatusEvent(SdnStatusEvent sdnStatusEvent) {
    LOGGER.info("handleSdnStatusEvent: sdnStatusEvent = {}", sdnStatusEvent);
}

方法2:将枚举类注册为SpEL全局变量(适用于多处复用场景)

如果需要在多个@EventListener或其他SpEL场景中复用该枚举类,可以在配置类中将枚举类注册为SpEL全局变量:

@Configuration
public class SpelConfig {
    @Bean
    public StandardEvaluationContext standardEvaluationContext() {
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("NEStatus", NEStatus.class);
        return context;
    }
}

之后在condition中即可直接使用变量调用枚举常量:

@EventListener(condition = "#sdnStatusEvent.getNeStatus() != null && #sdnStatusEvent.getNeStatus() == #NEStatus.Offline")
public void handleSdnStatusEvent(SdnStatusEvent sdnStatusEvent) {
    LOGGER.info("handleSdnStatusEvent: sdnStatusEvent = {}", sdnStatusEvent);
}

总结

推荐优先使用方法1,无需额外配置,代码简洁且完全满足需求;如果存在多处复用枚举类的场景,可选择方法2实现全局复用。

内容的提问来源于stack exchange,提问作者Alexei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 06:20:26