You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus中CDI Bean注入为null的问题求助

问题:Quarkus中部分CDI注入正常,TeamCodec的UserService却始终为null

我开发了一个简单的Quarkus后端应用,多数场景下CDI依赖注入运行正常,但存在一处依赖Bean注入后为null的异常情况。待注入的是用于从MongoDB加载数据的UserService类,代码如下:

UserService.java

@Singleton       // <= is this annotation correct? Or 
public class UserService {

    @Inject    // <= this all works fine
    MongoClient mongoClient;

    @ConfigProperty(name = "liquido.db-name")
    String dbName;

    public Optional<UserModel> getUserById(String userId) {
        // ... code to fetch user form DB ...
    }

}

另有一个实现org.mongodb.bson.CollectibleCodec的TeamCodec类,用于将MongoDB中的数据解码为POJO。该类中通过@Inject注入的UserService始终为null,调用其getUserById方法时失败,代码如下:

TeamCodec.java

@ApplicationScoped     // <= is this annotation correct?
public class TeamCodec implements CollectibleCodec<TeamModel> {

    @Inject
    UserService userService;     // <=== THIS IS ALWAYS NULL???

    @Override
    public TeamModel decode(BsonReader reader, DecoderContext decoderContext) {
        TeamModel teamModel = new TeamModel();
        reader.readStartDocument();

        userService.getUserById(...);  // <==== THIS FAILS
    }

}

原因与解决方案

核心原因:MongoDB Codec实例不受CDI容器管理

Quarkus的CDI注入仅对容器创建并管理的Bean实例生效。而MongoDB的CollectibleCodec实例通常由MongoDB驱动自身实例化(比如通过CodecRegistry注册时),并非Quarkus CDI容器创建,因此CDI无法对其执行依赖注入,导致userService始终为null。

具体解决步骤

  1. 让CDI容器接管TeamCodec的实例化
    不能依赖MongoDB驱动自动创建TeamCodec,需要通过CDI管理它的实例,再手动注册到MongoDB的CodecRegistry中。

  2. 调整TeamCodec的作用域(推荐)
    由于Codec通常是无状态的,使用@Singleton作用域比@ApplicationScoped更合适,可避免不必要的代理开销。

  3. 手动注册CDI管理的TeamCodec到MongoDB
    创建启动初始化逻辑,将TeamCodec实例注册到MongoDB的CodecRegistry:

    @ApplicationScoped
    public class MongoCodecInitializer {
    
        @Inject
        TeamCodec teamCodec;
    
        @Inject
        MongoClient mongoClient;
    
        void init(@Observes StartupEvent event) {
            CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
                mongoClient.getCodecRegistry(),
                CodecRegistries.fromCodecs(teamCodec)
            );
            // 使用该codecRegistry获取数据库/集合
            MongoDatabase db = mongoClient.getDatabase("liquido").withCodecRegistry(codecRegistry);
        }
    }
    
  4. 确认UserService的作用域
    UserService使用@Singleton是合理的,只要TeamCodec由CDI管理,就能正常注入UserService。

额外注意事项

  • 避免在Codec的decode方法中执行数据库操作,这可能引发线程安全或性能问题——MongoDB Codec设计初衷是轻量级数据转换,复杂关联逻辑建议放到后续业务流程中处理。

内容的提问来源于stack exchange,提问作者Robert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 22:35:18