Spring Boot中prometheus指标中缺失了JVM相关指标

2025/08/31 Spring Boot

一、问题

一个Spring Boot应用已经在配置中通过actuator和micrometer暴露了prometheus端点http://ip:port/actuator/prometheus,结合prometheus和grafana已使用在线上监控系统中了。

最近几周发现通过 /actuator/prometheus仍然能访问应用暴露的prometheus监控端点和部分指标,但是JVM相关的指标比如jvm_memory_used_bytes不见了,造成监控缺失。

二、原因

actuator、micrometer、prometheus和grafna最近配置没有做过调整。

看了一下应用最近的变更,在MyBatis自定义Configuration Bean中因为要定义SqlSessionFactory的Plugin(SQL Interceptor),@AutowiredMeterRegistry bean。去掉新增的@Autowired JVM相关指标就正常暴露了。

@Configuration
@MapperScan(value = { "com.**" }, sqlSessionFactoryRef = MybatisConfig.SQL_SESSION_FACTORY, sqlSessionTemplateRef = MybatisConfig.SQL_SESSION_TEMPLATE)
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
public class MybatisConfig {
        public static final String SQL_SESSION_FACTORY = "mainSqlSessionFactory";
    public static final String SQL_SESSION_TEMPLATE = "mainSqlSessionTemplate";
    
    @Autowired
    private MeterRegistry meterRegistry;

    @Bean(SQL_SESSION_FACTORY)
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
            SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        ...
        sessionFactoryBean.setPlugins(new SqlMonitorInterceptor(meterRegistry));
        ...
    

那么@Autowired一个MeterRegistry类咋就造成jvm_memory_used_bytes指标丢了呢?

这个跟Spring Boot的ConfigurationAutoConfiguration bean的初始化顺序有关。

简单来说,自定义的@Configuration 类优先级高于所有 Starter 的自动配置类。我们场景中prometheus指标正是通过MetricsAutoConfigurationJvmMetricsAutoConfiguration自动装配实现的。

我们自定义的MybatisConfig先初始化,初始化sqlSessionFactory bean的时候提前触发了MeterRegistry的初始化。但是这时候初始化的MeterRegistry是默认实现SimpleMeterRegistry,这个默认实现是不包括JVM指标的。等到MetricsAutoConfiguration初始化时,@ConditionalOnMissingBean(MeterRegistry.class)不匹配,就不会再初始化和配置MeterRegistry实例了。

三、解决

解决的方法是MybatisConfig初始化时不立刻创建 MeterRegistry,只注入一个代理。这可以通过在MybatisConfig类定义中针对meterRegistry添加@Lazy注解来实现。

   @Autowired
   @Lazy
   private MeterRegistry meterRegistry;

当 SqlMonitorInterceptor 最终使用 meterRegistry 时,取到的就是一个已经绑定了 JVM metrics 的 MeterRegistry(MetricsAutoConfiguration创建的)。

Search

    Table of Contents