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

Quarkus:如何在非CDI Bean中注入并使用CDI Bean?

问题根源

Quarkus的CDI依赖注入仅对容器托管的Bean生效(即添加了@ApplicationScoped、@Singleton、@RequestScoped等CDI注解的类)。你的Test类是普通Java类,不在容器管理范围内,所以@Inject注解不会被处理,注入的字段自然为null。

同时你的现有代码存在实例冲突问题:

  • Configuration类同时使用Quarkus的@Singleton注解和手动实现的静态单例模式,会生成两个完全独立的实例(容器管理的实例、getInstance()手动创建的实例)
  • ConfigurationProducer的@Produces方法返回的是手动创建的实例,脱离了容器管理范畴

解决方案

方案一:将Test类转为CDI Bean

如果Test类可以由容器管理,给它添加CDI作用域注解(比如@ApplicationScoped),让容器接管它的生命周期,@Inject即可正常生效:

@ApplicationScoped
public class Test {

    @Inject
    @Named("singletonConfiguration")
    Configuration configuration;

    public void doIt() {
        System.out.println("TEST");
        System.out.println(configuration); // 此时会注入容器管理的实例
    }
}

同时需要移除Configuration类的手动单例代码,避免实例冲突:

@Named("singletonConfiguration")
@Singleton
public class Configuration {
    // 移除静态INSTANCE和getInstance方法,由Quarkus全权管理单例
    public Configuration() {
        // 初始化逻辑写在这里
    }
}

方案二:在非Bean类中手动获取Bean实例

如果Test类必须是普通类(无法转为容器托管Bean),可以使用Quarkus提供的CDI.current()工具类,手动从容器中获取Bean实例:

import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.Named;
import jakarta.enterprise.inject.spi.CDI;
import jakarta.enterprise.util.AnnotationLiteral;

public class Test {

    public void doIt() {
        // 通过CDI API获取容器内的Configuration实例
        Configuration configuration = CDI.current()
                .select(Configuration.class, new NamedLiteral("singletonConfiguration"))
                .get();
        
        System.out.println("TEST");
        System.out.println(configuration);
    }

    // 辅助类:用于匹配@Named注解
    private static class NamedLiteral extends AnnotationLiteral<Named> implements Named {
        private final String value;

        public NamedLiteral(String value) {
            this.value = value;
        }

        @Override
        public String value() {
            return value;
        }
    }
}

同样需要移除Configuration类的手动单例代码,确保使用的是容器管理的实例。

方案三:修正Producer实现(可选)

如果想保留ConfigurationProducer,需要让它返回容器管理的实例,而非手动创建的:

@Named("producerConfiguration")
@Singleton
public class ConfigurationProducer {

    @Inject
    @Named("singletonConfiguration")
    Configuration config;

    @Produces
    @ApplicationScoped
    public Configuration produceConfiguration() {
        return config; // 返回容器托管的实例
    }
}

此时在转为Bean的Test类中,可直接注入Producer生成的实例:

@ApplicationScoped
public class Test {

    @Inject
    @Named("producerConfiguration")
    Configuration configuration;

    public void doIt() {
        System.out.println(configuration);
    }
}

注意事项
  • 禁止同时使用CDI的单例注解和手动单例模式,这会导致实例不一致,引发难以排查的问题。
  • Quarkus中@Singleton(JEE标准)和@ApplicationScoped(CDI作用域)的区别:@Singleton是严格单例,无代理;@ApplicationScoped默认也是单例,但支持代理特性,更适合大多数业务场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:33:10