Spring 自定义注解 为 BeanDefinition 添加 qualifier 信息 从而约束自动装配范围

为什么写这篇文章

        Spring 支持类型注入,并且可以通过Qualifier 或者Mate 调整类型注入的范围。但是通过自定义注解结合现有的 @Qualifier 使用起来有种种困难。

  • 将 @Qualifier 融合在自定义注解中,在使用 @AliasFor 遇到问题
  • 仅仅检查注解中的一部分内容是否匹配即可,Spring 不支持

添加自定义 Qualifier

package ann;

import java.lang.annotation.*;

/**
 * @author Jay
 */
@Target({ElementType.PARAMETER,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HandlerSelect {
    String value() default "";
}

组合 Qualifier 注解

package ann;

import java.lang.annotation.*;

/**
 * @author Jay
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MessageHandlerAnn {
    HandlerSelect qualifier();

    /**
     * 通过SpEL 表达式计算 #messageExt 的相关信息是否满足所有条件
     *
     * @return
     */
    String[] eLFilter() default "";

}

注册自定义限定符

    @Bean
    public CustomAutowireConfigurer customAutowireConfigurer() {
        CustomAutowireConfigurer configurer = new CustomAutowireConfigurer();
        configurer.setCustomQualifierTypes(Collections.singleton(HandlerSelect.class));
        return configurer;
    }

自定义注解处理工厂处理器

package config;

import ann.HandlerSelect;
import ann.MessageHandlerAnn;
import message.handler.MessageHandler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.stereotype.Component;

/**
 * @author Jay
 */
@Component
public class HandlerSelectQualifierProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 检查 实现了 MessageHandler 接口的 SpringBean 检查其是否标注有 MessageHandlerAnn 注解
        String[] beanNamesForType = beanFactory.getBeanNamesForType(MessageHandler.class);

        for (String beanName : beanNamesForType) {
            // 获取 Bean 定义对象
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            Class<?> beanClass = beanFactory.getType(beanName);

            // 检查是否有 MessageHandlerAnn 注解
            if (beanClass != null && beanClass.isAnnotationPresent(MessageHandlerAnn.class)) {
                // 创建并添加自定义的 qualifier 元素
                addCustomQualifier((AbstractBeanDefinition) beanDefinition, beanClass);
            }
        }
    }

    private static void addCustomQualifier(AbstractBeanDefinition beanDefinition, Class<?> beanClass) {
        // 创建 AutowireCandidateQualifier 实例(HandlerSelect 已经加入到 QualifierType 中)
        AutowireCandidateQualifier qualifier = new  AutowireCandidateQualifier(HandlerSelect.class);
        // 设置 qualifier 的值,例如:
        HandlerSelect qualifierValue = beanClass.getAnnotation(MessageHandlerAnn.class).qualifier();
        //  Attribute 的 Key 固定为 value, 其 value 值取自 HandlerSelect.qualifier.value
        qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, qualifierValue.value());

        // TODO 以上处理仅考虑 HandlerSelect 仅仅有一个限定描述符的场景。 如果需要拓展 HandlerSelect  的属性, 需要重新设计以上代码     

        // 添加限定符
        beanDefinition.addQualifier(qualifier);
    }
}

 MyMessageListener & MessageHandler

public interface MessageHandler {

}


public class MyMessageListener implements MessageListenerConcurrently, InitializingBean {

    final private List<MessageHandler<?>> messageHandlerList;

    public MyMessageListener(List<MessageHandler<?>> messageHandlerList) {
        this.messageHandlerList = messageHandlerList;
    }
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        for (MessageExt messageExt : msgs) {
        // ...
        }
    }
    
    @Override
    public void afterPropertiesSet() {
        System.out.println("MyMessageListener afterPropertiesSet");
        // messageHandlerList 不能为空
        if (ObjectUtils.isEmpty(this.messageHandlerList)) {
            log.error("messageHandlerList is empty");
            throw new RuntimeException("messageHandlerList is empty");
        } else {
            messageHandlerList.forEach(messageHandler -> {
                System.out.println(messageHandler.getClass().getName());
            });
        }
    }
}

配置&效果

待完善的地方 

  • 用于解析 @HandlerSelect 的 HandlerSelectQualifierProcessor 不能随着 HandlerSelect 的属性增加而 解析属性并增加对应的限定符
  • IDEA 工具无法预估 使用自定义的限定符号 还有哪些Bean

(截图红框显示为三个, 但实际myMessageListener0 依赖注入了T0T0、ToT1 而myMessageListener1 依赖注入了T1T0 )

相关博客: rocketmq Listener 还可以这样配置(基于SPEL\限定符号\自动连线)icon-default.png?t=N7T8http://t.csdnimg.cn/sE1Dk

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值