Quarkus Maven打包阶段检测Bean注入点引发依赖不满足问题排查
问题分析
打包阶段出现UnsatisfiedResolutionException的核心原因有两个:
- DevServices在打包阶段默认不激活:
quarkus dev模式下DevServices会自动启动容器并生成DevServicesResultBuildItem,但执行mvn package时DevServices默认关闭,你的createConfigBeanBuildStep因找不到DevServicesResultBuildItem抛出异常,导致SyntheticBeanBuildItem未生成,CDI验证时找不到FooConfigBean。 FooConfig的@ApplicationScoped注解冲突:你通过SyntheticBeanBuildItem提供Bean,但FooConfig标注了@ApplicationScoped,CDI会尝试扫描并实例化它,而你的无参构造是私有,CDI无法完成实例化,进一步加剧了依赖解析失败。
解决方案
1. 移除FooConfig的@ApplicationScoped注解
因为你完全通过SyntheticBeanBuildItem提供FooConfig实例,不需要CDI自动扫描这个类,移除注解避免冲突:
/** * Bean to inject */ // 移除@ApplicationScoped public class FooConfig { private String url; private String port; // Only for CDI injection @SuppressWarnings("unused") private FooConfig() {} public FooConfig(String url, String port) { this.url = url; this.port = port; } // getter/setter 保持不变 }
2. 添加Build Time配置作为打包阶段 fallback
为扩展添加Build Time配置属性,当打包阶段DevServices未启动时,使用默认配置生成FooConfig:
首先创建配置属性类:
import io.quarkus.runtime.annotations.ConfigRoot; import io.smallrye.config.ConfigItem; import io.quarkus.runtime.configuration.ConfigPhase; @ConfigRoot(name = "foo", phase = ConfigPhase.BUILD_TIME) public class FooBuildConfig { @ConfigItem(defaultValue = "localhost:8080") public String apiUrl; }
3. 修改BuildStep处理无DevServices的场景
修改createConfigBean BuildStep,兼容DevServices未启动的情况,使用配置属性生成Bean:
@Record(ExecutionTime.RUNTIME_INIT) @BuildStep public void createConfigBean( @Optional List<DevServicesResultBuildItem> devServicesResults, FooRecorder recorder, BuildProducer<SyntheticBeanBuildItem> beanProducer, FooBuildConfig buildConfig ) { String apiUrl; // 优先使用DevServices提供的地址 if (devServicesResults != null && !devServicesResults.isEmpty()) { apiUrl = devServicesResults.stream() .filter(r -> r.getName().equals(FooServiceContainer.CONTAINER_NAME)) .findFirst() .orElseThrow(() -> new IllegalStateException("Can't find foo-service url")) .getConfig().get("url"); apiUrl = "http://" + apiUrl; } else { // 打包阶段使用Build Time配置 apiUrl = "http://" + buildConfig.apiUrl; } // 修正端口分割逻辑:http://localhost:8080 分割后索引2为端口 String port = apiUrl.split(":")[2]; beanProducer.produce(SyntheticBeanBuildItem.configure(FooConfig.class) .unremovable() .setRuntimeInit() .runtimeValue(recorder.createConfig(apiUrl, port)) .done()); }
4. 调整Recorder方法
确保Recorder的createConfig方法参数正确,避免端口处理错误:
@Recorder public class FooServiceRecorder { public RuntimeValue<FooConfig> createConfig(String url, String port) { return new RuntimeValue<>(new FooConfig(url, port)); } }
验证
修改后执行mvn package,Quarkus会使用Build Time配置生成FooConfig Bean,CDI验证通过;运行quarkus dev时,依然会优先使用DevServices提供的地址,保持原有功能。
内容的提问来源于stack exchange,提问作者Scandinave
相关产品推荐
相关产品推荐

