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

SpringBoot整合Prometheus与RestTemplate时prometheusMeterRegistry循环依赖问题

问题解决方案:SpringBoot Actuator整合Prometheus与RestTemplate启动异常及指标展示问题

核心问题分析

  1. 循环依赖根源:启动时RestTemplate → MyRepo → MyHealthIndicator → 健康检查组件,与metricsRestTemplateCustomizer依赖的prometheusMeterRegistry形成循环链,导致Bean创建死锁。
  2. HealthContributorRegistry找不到:SpringBoot 2.7.x版本中,HealthContributorRegistry并非直接暴露的可注入Bean,需通过HealthEndpoint间接获取。
  3. RestTemplate指标失效:循环依赖导致MetricsRestTemplateCustomizer无法正常初始化,RestAPI指标无法被采集。

分步解决方案

1. 彻底打破循环依赖(无需开启allow-circular-references)

健康检查逻辑仅在应用启动后执行,无需在Bean初始化阶段就加载MyRepo和RestTemplate,通过@Lazy延迟注入打破循环:

@Component
public class MyHealthIndicator implements HealthIndicator {
    
    @Lazy
    @Autowired
    MyRepo myrepo;
    
    @Override
    public Health health() {
        // 修正字符串比较错误:用equals替代==
        return "SUCCESS".equals(myrepo.ping()) ? Health.UP.build() : Health.DOWN.build();
    }
}

2. 修复HealthContributorRegistry获取逻辑

调整MeterConfig,通过HealthEndpoint间接获取健康贡献者注册表,适配SpringBoot 2.7.x版本:

@Configuration
public class MeterConfig {
    @Bean
    public MeterRegistryCustomizer<MeterRegistry> healthRegistryCustomizer(HealthEndpoint healthEndpoint) {
        // 从主健康组中获取注册表
        HealthContributorRegistry healthRegistry = healthEndpoint.getHealthGroups().getPrimary().getContributorRegistry();
        
        return registry -> healthRegistry.stream()
                .forEach(namedContributor -> registry.gauge("health",
                        details(namedContributor),
                        healthRegistry, health -> {
                            Status status = ((HealthIndicator) health
                                    .getContributor(namedContributor.getName()))
                                    .getHealth(true)
                                    .getStatus();
                            return healthToCode(status);
                        }));
    }

    private static Iterable<Tag> details(NamedContributor<HealthContributor> contributor) {
        HealthContributor contrib = contributor.getContributor();
        if (!(contrib instanceof HealthIndicator)) {
            return List.of(Tag.of("name", contributor.getName()));
        }
        HealthIndicator healthContributor = (HealthIndicator) contrib;
        String name = contributor.getName();
        List<Tag> tagList = new ArrayList<>();
        tagList.add(Tag.of("name", name));
        try {
            // 避免启动时调用健康检查引发新的循环
            String details = healthContributor.getHealth(false).getDetails().toString();
            tagList.add(Tag.of("details", details));
        } catch (Exception e) {
            tagList.add(Tag.of("details", "unavailable"));
        }
        return tagList;
    }

    public static int healthToCode(Status status) {
        return status.equals(Status.UP) ? 1 : 0;
    }
}

3. 确保RestTemplate指标生效

添加必要配置并确认依赖:

  • application.yml配置:
    management:
      endpoints:
        web:
          exposure:
            include: prometheus,health
      metrics:
        export:
          prometheus:
            enabled: true
    
  • 确认依赖(SpringBoot 2.7.x版本):
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
    

验证步骤

  1. 移除spring.main.allow-circular-references=true配置
  2. 启动应用,检查无启动异常
  3. 访问/actuator/prometheus,确认存在http_client_requests_*(RestTemplate指标)和自定义health指标

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 23:55:31