RabbitMQ监听器动态传递队列名时出现SpEL异常的问题
问题分析与解决方案
异常原因
你遇到的SpelEvaluationException根源在于:
@RabbitListener中的SpEL表达式#{rabbitmqQueue}默认在Spring BeanFactory上下文查找对象,而非当前消费者bean的实例上下文,无法直接访问父类的私有字段。- 父类的
rabbitmqQueue是包私有权限,且未提供public getter方法,即便上下文正确也无法读取该字段值。
解决方案
方案一:通过this引用当前bean的属性
修改父类字段权限并添加getter,让SpEL能访问当前bean实例的队列名:
public abstract class RabbitmqConsumerService { protected String rabbitmqQueue; // 修改为protected权限,子类可访问 protected final Log log = LogFactory.getLog(getClass()); // 补充日志实例 protected RabbitmqConsumerService(String rabbitmqQueue) { this.rabbitmqQueue = rabbitmqQueue; } // 添加public getter方法,供SpEL读取 public String getRabbitmqQueue() { return rabbitmqQueue; } /** * 通用消息消费方法 * @param message */ @RabbitListener(queues = "#{this.rabbitmqQueue}") // 使用this指向当前bean实例 public void consume(String message) { LoggingUtils.debug(log, "Received Message: {}", message); } }
子类代码保持不变即可,构造传入的队列名会通过getter被SpEL正确读取。
方案二:子类自行配置监听队列
将@RabbitListener移到子类的实现方法上,直接指定队列名,逻辑更直观:
父类修改(移除监听注解,改为抽象方法)
public abstract class RabbitmqConsumerService { protected String rabbitmqQueue; protected final Log log = LogFactory.getLog(getClass()); protected RabbitmqConsumerService(String rabbitmqQueue) { this.rabbitmqQueue = rabbitmqQueue; } /** * 通用消息消费抽象方法 * @param message */ public abstract void consume(String message); }
子类实现(添加监听注解)
public class NodeHierarchyMessageReceiver<V> extends RabbitmqConsumerService { @Autowired NodeHierarchyService nodeHierarchyService; public NodeHierarchyMessageReceiver(@Value("${mt.message.queue}") String queueName2) { super(queueName2); } @Override @RabbitListener(queues = "#{this.rabbitmqQueue}") // 直接引用当前bean的队列属性 public void consume(String message) { LoggingUtils.debug(log, "Message got received:{}", message); // 业务逻辑实现 } }
如果队列名仅该子类使用,也可以直接用配置值简化:queues = "${mt.message.queue}",无需依赖父类字段。
内容的提问来源于stack exchange,提问作者bharathi
相关产品推荐
相关产品推荐

