@RocketMQMessageListener属性支持SPEL

2 篇文章 0 订阅
1 篇文章 0 订阅

问题

@RocketMQMessageListener的属性(例如:topic和consumerGroup等)仅支持环境变量替换,无法支持SPEL。无法像SpringMVC的@RequestParam一样。

ListenerContainerConfiguration下通过实现SmartInitializingSingleton后,在afterSingletonsInstantiated中进行处理和注册DefaultRocketMQListenerContainer。

如下图,处理过程中从注解获取的属性仅进行了环境变量替换。未支持SPEL。
在这里插入图片描述

解决方法

1、从源码得知,方法的执行是通过SmartInitializingSingleton进行触发,因此我们可以提前获取,注解并扩展所需的功能。

由于SmartInitializingSingleton是在bean全部执行完后,再进行的处理。因此可以自定义bean触发扩展逻辑处理

2、要支持变量替换,可以参考@RequestParam的逻辑实现

org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver#resolveArgument方法内resolveEmbeddedValuesAndExpressions的处理逻辑

在这里插入图片描述

具体实现代码:

@Component
public class RocketMQListenerExtendHandler implements InitializingBean, BeanFactoryAware {

    @Autowired
    private ApplicationContext applicationContext;

    private ConfigurableBeanFactory configurableBeanFactory;
    private BeanExpressionContext expressionContext;

    @Override
    public void afterPropertiesSet() throws Exception {
        //获取RocketMQMessageListener相关bean
        Map<String,Object> beans = applicationContext.getBeansWithAnnotation(RocketMQMessageListener.class);
        for (Object bean : beans.values()){
            if (!RocketMQListener.class.isAssignableFrom(bean.getClass())) {
                continue;
            }

            //通过反射获取注解内的属性
            Class<?> clazz = AopProxyUtils.ultimateTargetClass(bean);
            RocketMQMessageListener annotation = clazz.getAnnotation(RocketMQMessageListener.class);
            InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
            Field field = invocationHandler.getClass().getDeclaredField("memberValues");
            field.setAccessible(true);
            Map<String, Object> memberValues = (Map<String, Object>) field.get(invocationHandler);
            for (Map.Entry<String,Object> entry: memberValues.entrySet()) {
                if(Objects.nonNull(entry) && (entry.getValue() instanceof String)){
                   //根据注解属性进行自定义扩展
                    memberValues.put(entry.getKey(), handlePlaceholderAndSPEL((String) entry.getValue()));
                }
            }
        }
    }

    //根据注解属性进行自定义扩展
    private String handlePlaceholderAndSPEL(String param) {
        return (String)resolveEmbeddedValuesAndExpressions(param);
    }

    //仿照@RequestParam的实现逻辑进行 变量替换 和 SPEL表达式执行
    private Object resolveEmbeddedValuesAndExpressions(String value) {
        if (this.configurableBeanFactory != null && this.expressionContext != null) {
            String placeholdersResolved = this.configurableBeanFactory.resolveEmbeddedValue(value);
            BeanExpressionResolver exprResolver = this.configurableBeanFactory.getBeanExpressionResolver();
            return exprResolver == null ? placeholdersResolved : exprResolver.evaluate(placeholdersResolved, this.expressionContext);
        } else {
            return value;
        }
    }


    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        if (beanFactory instanceof ConfigurableBeanFactory) {
            this.configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
            this.expressionContext = configurableBeanFactory != null ? new BeanExpressionContext(configurableBeanFactory, new RequestScope()) : null;
        }
    }



}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值