JBeret SE中CDI注入Logger至Batchlet失败问题求助
我来帮你梳理下这个问题的核心原因和解决思路:
问题根源
JBeret的Batch组件(比如Batchlet、Chunk)默认是由Batch运行时自身创建实例的,并没有完全纳入CDI容器的上下文管理中。而你的SampleBatchletTest和Server类是直接由CDI容器初始化管理的,所以能正常注入自定义Producer提供的Logger;但Batchlet实例绕过了CDI容器,自然无法触发你的LoggerProducer逻辑,只能通过@BatchProperty这种JBeret专属的方式注入JDK自带的java.util.logging.Logger。
具体解决步骤
1. 将Batchlet纳入CDI容器管理
首先要让Weld容器明确管理你的SampleBatchlet,修改测试类中的WeldInitiator配置,把SampleBatchlet加入到要初始化的bean列表中:
@WeldSetup public WeldInitiator weld = WeldInitiator .from(LoggerProducer.class, SampleBatchlet.class, Server.class) .activate(RequestScoped.class, ApplicationScoped.class) .build();
这样Weld会把Batchlet作为CDI bean管理,Batch运行时创建实例时会优先从CDI容器获取。
2. 确保LoggerProducer的作用域正确
给你的LoggerProducer添加合适的作用域注解(比如@ApplicationScoped),避免因作用域缺失导致注入失败:
@ApplicationScoped public class LoggerProducer { @Produces public Logger produceLogger(InjectionPoint injectionPoint) { return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); } }
这里@Produces的默认作用域是@Dependent,配合@ApplicationScoped的Producer类可以保证Producer的生命周期稳定。
3. 恢复Batchlet中的纯CDI注入
去掉@BatchProperty注解,回到标准的CDI注入方式:
@Named public class SampleBatchlet extends AbstractBatchlet { @Inject @BatchProperty(name = "foo") String foo; @Inject StepContext stepContext; @Inject Logger logger; // 只保留@Inject @Override public String process() throws Exception { final String say = stepContext.getProperties().getProperty("say"); logger.info("hello foolish"); // 现在可以用自定义Logger了 return null; } }
4. 配置JBeret使用CDI BeanManager
在测试类的初始化阶段,把Weld的BeanManager传递给JBeret,确保它能识别CDI bean:
@BeforeEach void setupBatchCdiIntegration() { BeanManager beanManager = weld.getBeanManager(); // 告诉JBeret使用CDI的BeanManager来获取组件 System.setProperty("javax.enterprise.inject.spi.BeanManager", beanManager.toString()); }
额外说明
如果是在非测试的JBeret SE环境中,你需要确保Weld容器启动时能扫描到SampleBatchlet、LoggerProducer等类,并且在启动Batch运行前初始化CDI容器,让JBeret能感知到CDI上下文。
内容的提问来源于stack exchange,提问作者Fabrizio Stellato

