如何避免JavaEE中重复编写多个@Produces方法?
解决JavaEE中批量注册@Produces类的方案
要实现新增Dao类时无需手动编写@Produces方法,可通过**CDI可移植扩展(Portable Extension)**结合自定义注解来自动扫描并注册生产者,以下是具体实现步骤:
1. 定义自定义注解标记目标Dao类
创建一个限定符注解,用于标记需要自动生成生产者的Dao接口:
import javax.inject.Qualifier; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Qualifier @Target(TYPE) @Retention(RUNTIME) public @interface JdbiDao { }
2. 实现CDI扩展类
编写CDI扩展,在容器启动时扫描所有带@JdbiDao的类,并动态注册生产者Bean:
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; import javax.enterprise.inject.spi.*; import javax.inject.Inject; import org.jdbi.v3.core.Jdbi; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; public class JdbiDaoExtension implements Extension { private final Map<Class<?>, Bean<?>> daoBeanMap = new HashMap<>(); // 扫描并收集所有带@JdbiDao的类 <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat) { if (pat.getAnnotatedType().isAnnotationPresent(JdbiDao.class)) { Class<T> daoClass = pat.getAnnotatedType().getJavaClass(); daoBeanMap.put(daoClass, new DaoProducerBean<>(daoClass)); pat.veto(); // 让CDI忽略原始类,使用我们自定义的Bean } } // 在Bean发现阶段完成后注册自定义生产者 void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) { daoBeanMap.values().forEach(abd::addBean); } // 自定义生产者Bean实现 private static class DaoProducerBean<T> implements Bean<T> { private final Class<T> daoClass; public DaoProducerBean(Class<T> daoClass) { this.daoClass = daoClass; } @Override public T create(CreationalContext<T> ctx) { // 获取已注入的Jdbi实例(需确保Jdbi已被注册为CDI Bean) Jdbi jdbi = CDI.current().select(Jdbi.class).get(); return jdbi.onDemand(daoClass); } @Override public void destroy(T instance, CreationalContext<T> ctx) { // JDBI的onDemand代理无需手动销毁,留空即可 } @Override public Set<Type> getTypes() { return Collections.singleton(daoClass); } @Override public Set<Annotation> getQualifiers() { return Collections.singleton(new JdbiDaoImpl()); } @Override public Class<? extends Annotation> getScope() { return ApplicationScoped.class; // 可根据需求改为Dependent或其他作用域 } @Override public String getName() { return daoClass.getSimpleName(); } @Override public Set<Class<? extends Annotation>> getStereotypes() { return Collections.emptySet(); } @Override public boolean isAlternative() { return false; } @Override public boolean isNullable() { return false; } @Override public Set<InjectionPoint> getInjectionPoints() { return Collections.emptySet(); } } // 实现@JdbiDao注解的实例类 private static class JdbiDaoImpl implements JdbiDao { @Override public Class<? extends Annotation> annotationType() { return JdbiDao.class; } } }
3. 配置CDI扩展
在项目的META-INF/services/javax.enterprise.inject.spi.Extension文件中添加扩展类的全限定名,让CDI容器加载该扩展:
com.yourpackage.JdbiDaoExtension
(替换com.yourpackage为实际的包路径)
4. 注册Jdbi为CDI Bean
确保Jdbi实例可被CDI注入,可通过生产者类实现:
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; import org.jdbi.v3.core.Jdbi; @ApplicationScoped public class JdbiProducer { @Produces public Jdbi createJdbi() { // 初始化Jdbi,替换为你的数据库连接配置 return Jdbi.create("jdbc:mysql://localhost:3306/your_db", "username", "password"); } }
5. 使用方式
给需要自动注册的Dao接口添加@JdbiDao注解:
@JdbiDao public interface DaoX { // Dao方法定义 } @JdbiDao public interface DaoY { // Dao方法定义 }
之后就可以直接通过@Inject注入这些Dao,无需手动编写@Produces方法:
@Inject private DaoX daoX; @Inject private DaoY daoY;
内容的提问来源于stack exchange,提问作者Matej Delinčák
相关产品推荐
相关产品推荐

