Picocli应用中如何通过@Inject注入SeContainer/CDI实例本身?
无特定CDI实现依赖的Picocli工厂实现方案
问题核心原因
注入SeContainer失败是因为CDI规范并未将SeContainer定义为可直接注入的内置Bean——它是容器自身的实例,规范仅提供CDI.current()这一标准方式获取当前容器,而非依赖注入。
可行解决方案
方案1:基于CDI.current()的规范实现
在绝大多数CLI单容器场景下,CDI.current()是可靠的。若担心多容器场景,可通过@PostConstruct提前缓存容器实例,确保获取的是创建当前Bean的容器:
@ApplicationScoped public class PicocliCDIFactory implements CommandLine.IFactory { private CDI<Object> cdi; @PostConstruct void init() { this.cdi = CDI.current(); } @Override public <K> K create(Class<K> cls) throws Exception { return cdi.select(cls).get(); } @PreDestroy void cleanup() { if (cdi != null) { cdi.close(); } } }
- 用
CDI<Object>替代具体容器类型,完全遵循CDI规范,无任何实现依赖。 - 多容器场景下,
@PostConstruct在容器内部线程执行,此时CDI.current()绑定的正是创建该工厂Bean的容器,可保证实例正确性。
方案2:通过Producer转为可注入Bean
若偏好依赖注入的代码风格,可自定义Producer将CDI实例转为可注入Bean:
@ApplicationScoped public class CDIContainerProducer { @Produces @ApplicationScoped public CDI<Object> produceCDIContainer() { return CDI.current(); } }
修改工厂类实现注入:
@ApplicationScoped public class PicocliCDIFactory implements CommandLine.IFactory { private final CDI<Object> cdi; @Inject public PicocliCDIFactory(CDI<Object> cdi) { this.cdi = cdi; } @Override public <K> K create(Class<K> cls) throws Exception { return cdi.select(cls).get(); } }
该方案本质仍基于CDI.current(),但通过Producer适配为依赖注入模式,保持实现中立性。
关键说明
- CDI规范未定义
SeContainer的注入支持,它是Jakarta EE SE容器的入口类,仅能通过SeContainerInitializer创建或CDI.current()获取。 - CLI应用通常不会启动多容器,多容器场景只要保证工厂Bean部署与
CDI.current()调用在同一容器上下文线程中,即可获取正确实例。
内容的提问来源于stack exchange,提问作者QuantasImpossibile
相关产品推荐
相关产品推荐

