为何Weld会忽略injectionTarget.getInjectionPoints()的返回值?
问题分析与解答
核心问题梳理
你通过监听ProcessInjectionTarget的可移植扩展,采用规范文档记载的机制设置了自定义InjectionTarget:
- 该自定义实现除特定逻辑外,其余操作均转发给容器提供的原生
InjectionTarget; - 你向自定义
InjectionTarget的getInjectionPoints()返回集合中添加了一个针对无@Inject注解普通字段的自定义注入点; - 无匹配Bean时,Weld抛出无值提供者的异常(符合预期);但引入适配Bean后,Weld不再报错,目标字段却始终为
null; - 排查发现Weld的
ResourceInjector子类实现未使用injectionTarget.getInjectionPoints()的返回值,而是直接从Bean归档中读取注入点信息。
1. InjectionTarget.getInjectionPoints()的规范意义
根据Jakarta CDI规范,InjectionTarget.getInjectionPoints()的核心作用是告知容器当前注入目标需要处理的全部注入点,容器应当严格遵循这个返回值,将其作为注入阶段需要填充的“插槽”集合。
自定义InjectionTarget时重写该方法、返回扩展后的注入点集合是完全符合规范的用法,具备明确的扩展价值:它允许开发者通过程序方式为目标类添加额外注入需求,无需修改类源码的注解配置。
2. Weld实现的缺陷定位
你提到的ResourceInjector逻辑中,直接从Bean的增强注解类型(EnhancedAnnotatedType)中获取注入点,而非调用InjectionTarget.getInjectionPoints()获取最终的注入点集合,这属于Weld的实现不符合CDI规范的问题。这种设计跳过了自定义InjectionTarget对注入点的扩展逻辑,导致注入阶段完全忽略了你添加的自定义注入点。
3. 解决方案与临时处理方案
- 推动官方修复:你已在weld-dev邮件列表提出该问题,可跟进沟通,推动Weld团队修复
ResourceInjector的逻辑,确保注入阶段使用InjectionTarget.getInjectionPoints()的返回值; - 临时 workaround:若需快速解决问题,可在自定义
InjectionTarget的inject()方法中手动处理自定义注入点的注入逻辑,不依赖容器自动流程:@Override public void inject(T instance, CreationalContext<T> ctx) { // 先执行原生InjectionTarget的注入逻辑 delegate.inject(instance, ctx); // 手动处理自定义注入点 for (InjectionPoint customIp : yourCustomInjectionPoints) { Field targetField = (Field) customIp.getMember(); targetField.setAccessible(true); try { // 获取注入值并设置到目标字段 Object injectedValue = customIp.getBean().create(ctx); targetField.set(instance, injectedValue); } catch (IllegalAccessException e) { throw new RuntimeException("Failed to inject custom field", e); } } }
4. 结论
从CDI规范层面来看:
- 实现
InjectionTarget.getInjectionPoints()返回非空扩展集合完全有意义,这是CDI扩展机制的核心设计场景之一; - 容器必须遵循
InjectionTarget上报的注入点集合,这是保证扩展合法性的基础。
Weld当前的ResourceInjector实现存在不符合规范的缺陷,导致自定义注入点在注入阶段被忽略。
内容的提问来源于stack exchange,提问作者Laird Nelson
相关产品推荐
相关产品推荐

