Quarkus多模块项目自定义ConfigSource无法正常注册问题
解决方案
核心问题分析
- 你的自定义
ConfigSource依赖CDI注解(@ApplicationScope、@Inject),但Quarkus在启动早期加载配置时,CDI容器尚未完全初始化该Bean,导致开发模式下配置源未被注册到配置系统中。 - 添加
@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
相关产品推荐
相关产品推荐

