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

Quarkus多模块项目自定义ConfigSource无法正常注册问题

解决方案

核心问题分析

  1. 你的自定义ConfigSource依赖CDI注解(@ApplicationScope、@Inject),但Quarkus在启动早期加载配置时,CDI容器尚未完全初始化该Bean,导致开发模式下配置源未被注册到配置系统中。
  2. 添加@Startup注解后,Bean会在启动后期初始化,此时配置解析已完成,配置系统无法复用其属性;同时可能因ordinal设置或加载顺序问题,覆盖了默认的application.properties配置源,导致无法读取其中的属性。

修复步骤

1. 改用ConfigSourceFactory实现配置源

Quarkus推荐使用ConfigSourceFactory替代直接实现ConfigSource,它支持在配置加载阶段安全获取CDI依赖,适配Quarkus的启动流程。

创建配置源工厂类
import io.quarkus.arc.Arc;
import io.quarkus.runtime.annotations.StaticInitSafe;
import io.quarkus.microprofile.config.spi.ConfigSourceFactory;
import org.eclipse.microprofile.config.spi.ConfigSource;

import jakarta.persistence.EntityManager;
import java.util.Collections;
import java.util.List;

@StaticInitSafe
public class MyCustomConfigSourceFactory implements ConfigSourceFactory {

    @Override
    public List<ConfigSource> getConfigSources(ConfigSourceContext context) {
        // 通过Arc容器获取EntityManager,适配静态初始化阶段的依赖获取
        EntityManager entityManager = Arc.container().instance(EntityManager.class).get();
        return Collections.singletonList(new MyCustomConfigSource(entityManager));
    }
}
修改自定义配置源类

移除CDI相关注解,改用构造注入获取EntityManager,并确保getValue方法在属性不存在时返回null(触发低优先级配置源的fallback):

import org.eclipse.microprofile.config.spi.ConfigSource;

import jakarta.persistence.EntityManager;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class MyCustomConfigSource implements ConfigSource {

    private final EntityManager entityManager;

    // 构造注入EntityManager
    public MyCustomConfigSource(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public int getOrdinal() {
        // 设置为200,高于默认application.properties的100,确保数据库配置优先
        return 200;
    }

    @Override
    public Set<String> getPropertyNames() {
        // 从数据库查询所有配置键
        return entityManager.createQuery("SELECT c.key FROM ConfigEntity c", String.class)
                .getResultStream()
                .collect(Collectors.toSet());
    }

    @Override
    public Map<String, String> getProperties() {
        // 从数据库查询所有键值对
        return entityManager.createQuery("SELECT c.key, c.value FROM ConfigEntity c", Object[].class)
                .getResultStream()
                .collect(Collectors.toMap(arr -> (String) arr[0], arr -> (String) arr[1]));
    }

    @Override
    public String getValue(String key) {
        // 查询单个属性,不存在则返回null,自动fallback到低优先级配置源
        ConfigEntity config = entityManager.find(ConfigEntity.class, key);
        return config != null ? config.getValue() : null;
    }

    @Override
    public String getName() {
        return "DatabaseConfigSource";
    }
}

2. 注册配置源工厂

  • 删除module2中原来的META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource文件
  • 创建新文件META-INF/services/io.quarkus.microprofile.config.spi.ConfigSourceFactory,内容为你的工厂类全类名(例如com.yourpackage.MyCustomConfigSourceFactory)

3. 移除不必要的注解

删除原MyCustomConfigSource中的@ApplicationScope和@Transactional注解:

  • @ApplicationScope不再需要,因为工厂模式会直接实例化配置源
  • @Transactional可移除,只读查询无需事务;若需事务,可在查询方法内手动开启

验证效果

启动开发模式后,配置系统会优先从数据库读取MyPropertyFromDB,若数据库不存在该属性,会自动从application.properties中读取,同时不会出现配置源未注册的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 15:35:28