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

如何基于多限定符注解动态选择CDI Processor Bean?

解决CDI中基于多限定符动态选择Bean的问题

问题背景

现有多个Processor类,每个负责处理1-2个特定key的CSV行数据。通过CDI注入Instance<Processor>后,原本可以根据每行的key,用processors.select(new ProcessorQualifier(key))匹配对应Processor。但当需要让一个Processor同时处理多个key时,重复添加@ProcAnnotation会触发编译错误,创建可重复注解容器后,又无法通过原有的select方法匹配到对应Bean。

解决方案步骤

1. 修正可重复注解的定义

首先要正确配置可重复注解的结构,原有的@ProcAnnotations配置有误,需要调整:

调整@ProcAnnotation(单个限定符注解)

添加@Repeatable指定容器注解,确保编译器允许重复使用该注解:

@Retention(RUNTIME)
@Qualifier
@Target({TYPE})
@Repeatable(ProcAnnotations.class) // 指定容器注解
public @interface ProcAnnotation {
    ProcTypeEnum type();
}

调整@ProcAnnotations(容器注解)

移除多余的@Qualifier、@Stereotype等注解,它仅作为多个@ProcAnnotation的容器:

@Retention(RUNTIME)
@Target({TYPE})
public @interface ProcAnnotations {
    ProcAnnotation[] value();
}

2. 给Processor添加多key支持

现在可以直接给同一个Processor添加多个@ProcAnnotation注解,编译器不会报错:

@ProcAnnotation(type = ProcTypeEnum.key1)
@ProcAnnotation(type = ProcTypeEnum.key2)
class Key1AndKey2Processor implements Processor {
    @Override
    public void processLine(String text) {
        // 处理key1和key2的逻辑
    }
}

3. 修改动态选择逻辑

CDI的Instance.select(Qualifier)默认是精确匹配单个限定符,无法匹配带有多个限定符的Bean。因此需要换一种方式:提前构建key到Processor的映射,或遍历实例检查注解。

方式一:初始化时构建映射(推荐)

在Parser初始化阶段,把所有Processor按对应的key分组存入Map,后续直接通过key查询,性能更优:

class Parser {
    @Inject
    @Any
    Instance<Processor> processors;
    private Map<ProcTypeEnum, List<Processor>> processorMap;

    @PostConstruct
    void initProcessorMap() {
        processorMap = new HashMap<>();
        for (Processor processor : processors) {
            // getAnnotationsByType会自动解开@ProcAnnotations容器,返回所有单个@ProcAnnotation
            ProcAnnotation[] annotations = processor.getClass().getAnnotationsByType(ProcAnnotation.class);
            for (ProcAnnotation anno : annotations) {
                processorMap.computeIfAbsent(anno.type(), k -> new ArrayList<>()).add(processor);
            }
        }
    }

    public void parseCsv(BufferedReader reader) throws IOException {
        String text;
        while (null != (text = reader.readLine())) {
            String keyStr = getKeyFromLine(text);
            ProcTypeEnum key = ProcTypeEnum.valueOf(keyStr);
            List<Processor> matchedProcessors = processorMap.get(key);
            if (matchedProcessors != null && !matchedProcessors.isEmpty()) {
                // 此处假设每个key对应一个Processor,可根据需求调整逻辑
                matchedProcessors.get(0).processLine(text);
            }
        }
    }

    private String getKeyFromLine(String text) {
        // 提取行中key的逻辑
        return "";
    }
}

方式二:遍历实例实时匹配

如果不需要提前初始化,也可以每次处理行时遍历所有Processor实例,检查是否支持当前key:

class Parser {
    @Inject
    @Any
    Instance<Processor> processors;

    public void parseCsv(BufferedReader reader) throws IOException {
        String text;
        while (null != (text = reader.readLine())) {
            String keyStr = getKeyFromLine(text);
            ProcTypeEnum key = ProcTypeEnum.valueOf(keyStr);
            
            for (Processor processor : processors) {
                ProcAnnotation[] annotations = processor.getClass().getAnnotationsByType(ProcAnnotation.class);
                for (ProcAnnotation anno : annotations) {
                    if (anno.type() == key) {
                        processor.processLine(text);
                        break;
                    }
                }
            }
        }
    }

    private String getKeyFromLine(String text) {
        // 提取行中key的逻辑
        return "";
    }
}

关键说明

getAnnotationsByType(ProcAnnotation.class)方法会自动处理可重复注解的容器,直接返回所有添加的@ProcAnnotation实例,无需手动解析@ProcAnnotations容器注解,这是Java反射API对可重复注解的原生支持。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 05:54:59