CDI注入继承Bean的子接口报UnsatisfiedResolutionException异常
自定义MongoDB Repository子接口注入失败问题
问题背景
开发自定义MongoDB Repository组件处理业务上下文相关事务,期望通过接口对外暴露能力,在服务层注入接口而非具体实现类时出现依赖注入异常。
现有代码结构
- 通用基础Repository接口
public interface MongoRepositoryActions<T> { <S extends T> S save(S entity); }
- 通用基础Repository实现类
import com.mongodb.client.MongoClient; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; @ApplicationScoped public class BaseMongoRepository<T> implements MongoRepositoryActions<T> { @Inject MongoClient mongoClient; public <O extends T> O save(O object) { // 执行业务自定义逻辑 insertOperation(object); return object; } }
- 业务维度自定义Repository子接口
public interface FruitRepository extends MongoRepositoryActions<Fruit> { }
- 服务层注入逻辑
import com.abinbev.b2b.core.MongoRepositoryActions; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; @ApplicationScoped public class FruitService { @Inject MongoRepositoryActions<Fruit> fruitRepository; // 注入正常 @Inject FruitRepository repository; // 注入失败 public Fruit saveFruit(Fruit fruit) { return fruitRepository.save(fruit); } }
报错信息
注入FruitRepository类型Bean时应用启动失败,抛出异常:
javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type com.abinbev.b2b.core.fruit.FruitRepository and qualifiers [@Default]
尝试给接口添加CDI相关注解后问题仍未解决。
根本原因
CDI容器的Bean类型匹配遵循明确的类型关联规则:加了@ApplicationScoped注解的BaseMongoRepository<T>,容器只会将实现类本身、以及*该类直接实现的接口MongoRepositoryActions<T>*作为这个Bean的可匹配类型。
你自定义的FruitRepository是MongoRepositoryActions<Fruit>的子接口,既不是BaseMongoRepository直接实现的接口,也和BaseMongoRepository没有继承/实现关联,容器不会自动把现有通用Bean匹配给FruitRepository类型的注入点,因此抛出依赖找不到的错误。
解决方案
- 方案1:为每个业务Repository添加空实现类(无兼容成本,优先选择)
这是最直接、没有额外依赖的实现方式,每个业务子接口对应一个轻量实现类,继承通用基类、实现对应业务接口即可,不需要重复编写通用CRUD逻辑:
@ApplicationScoped public class FruitRepositoryImpl extends BaseMongoRepository<Fruit> implements FruitRepository { // 所有通用方法直接从BaseMongoRepository继承,无需额外编码 }
添加该类后,CDI容器会自动将这个Bean注册为FruitRepository类型的可注入实例,注入点可正常初始化。
- 方案2:通过CDI扩展动态注册Bean
如果后续业务Repository数量较多,不想为每个接口重复编写空实现类,可以自定义CDI扩展:在容器启动的AfterBeanDiscovery阶段,扫描所有继承了MongoRepositoryActions的业务子接口,动态为每个接口创建基于BaseMongoRepository的代理Bean并注册到容器中,即可实现类似Spring Data MongoDB只写接口、无需手动写实现的效果。
内容的提问来源于stack exchange,提问作者Johnnes Souza
相关产品推荐
相关产品推荐

