如何以编程方式动态注入抽象类的CDI托管Bean实例?
动态生成GenericScheduleController实例的可行方案
你的需求是可行的,但因为GenericScheduleController是抽象类无法直接实例化,需要通过动态生成子类+CDI编程式注入的方式实现。以下是具体实现思路和代码示例:
核心思路
- 动态生成
GenericScheduleController的子类,实现抽象方法getLabel(),让它返回传入的chaine参数。 - 通过CDI的编程式API(
Instance)获取该动态子类的实例,确保CDI自动处理@Inject依赖注入和@PostConstruct生命周期方法。
具体实现(基于ByteBuddy字节码生成库)
ByteBuddy是常用的字节码生成工具,能方便地动态创建子类。
1. 引入ByteBuddy依赖(Maven示例)
<dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.14.11</version> </dependency>
2. 编写工厂方法实现
import net.bytebuddy.ByteBuddy; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.matcher.ElementMatchers; import javax.enterprise.context.Dependent; import javax.enterprise.inject.Instance; import javax.inject.Inject; public class ScheduleControllerFactory { @Inject private Instance<GenericScheduleController> controllerInstance; public GenericScheduleController getScheduleController(String chaine) { try { // 动态生成子类:实现getLabel()返回指定字符串,并添加@Dependent作用域 Class<? extends GenericScheduleController> dynamicSubclass = new ByteBuddy() .subclass(GenericScheduleController.class) .annotateWith(Dependent.class) // 标记为CDI的依赖作用域,每次获取新实例 .method(ElementMatchers.named("getLabel")) .intercept(MethodDelegation.to(new Object() { @SuppressWarnings("unused") public String getLabel() { return chaine; } })) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); // 通过CDI Instance获取实例,自动处理依赖注入和@PostConstruct return controllerInstance.select(dynamicSubclass).get(); } catch (Exception e) { throw new RuntimeException("生成动态ScheduleController失败", e); } } }
关键细节说明
- 动态子类作用域:添加
@Dependent注解确保每次调用getScheduleController()都能获取新实例,符合你的需求。 - CDI生命周期处理:通过
Instance.select().get()获取实例时,CDI会自动注入Service实例,并执行@PostConstruct的init()方法,此时getLabel()返回的就是传入的chaine参数。 - 字节码生成工具选择:如果不想用ByteBuddy,也可以用CGLIB,但ByteBuddy的API更简洁易用。Java原生的
Proxy只能代理接口,无法处理抽象类,所以不适用。
内容的提问来源于stack exchange,提问作者olivier P
相关产品推荐
相关产品推荐

