Skip to content

OkapiMicrometerAutoConfiguration silently skipped on Spring Boot 3.5.x due to wrong @AutoConfigureAfter target #36

@pdudzinsky

Description

@pdudzinsky

Summary

OkapiMicrometerAutoConfiguration (in okapi-spring-boot) declares @AutoConfigureAfter against the Spring Boot 4.0 package layout. On Spring Boot 3.5.x — which the README lists as supported — that class does not exist, the hint is silently dropped, and the auto-config can be evaluated before MeterRegistry is registered. When that happens, @ConditionalOnBean(MeterRegistry::class) fails and the entire auto-config (listener, metrics, refresher) is skipped — leaving consumers without metrics and breaking any code that depends on MicrometerOutboxListener.

Affected versions

  • okapi 0.2.0 (and likely earlier — bug is in okapi-spring-boot)
  • Spring Boot 3.5.x (verified on 3.5.7)
  • README compatibility matrix says: Spring Boot 3.5.x, 4.0.x

Symptoms

In a Spring Boot 3.5.x application with okapi-spring-boot + okapi-micrometer on the classpath and a working MeterRegistry (e.g. micrometer-registry-prometheus):

  • No okapi_* metrics appear at /actuator/prometheus.
  • MicrometerOutboxListener, MicrometerOutboxMetrics, OutboxMetricsRefresher beans are absent.
  • Application code that injects any of these fails at startup with UnsatisfiedDependencyException.

Root cause

OkapiMicrometerAutoConfiguration.kt:

@AutoConfiguration
@AutoConfigureAfter(
    name = ["org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration"],
)
@ConditionalOnClass(name = ["io.micrometer.core.instrument.MeterRegistry"])
@ConditionalOnBean(MeterRegistry::class)
@EnableConfigurationProperties(OkapiMetricsProperties::class)
class OkapiMicrometerAutoConfiguration { ... }

The referenced class lives at org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration only in Spring Boot 4.0. In 3.5.x the same class is at org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration.

@AutoConfigureAfter(name = ...) is tolerant of missing classes — the hint is silently ignored, leaving the relative ordering between OkapiMicrometerAutoConfiguration and Spring Boot's metrics auto-configurations undefined. In practice on 3.5.7 our auto-config is evaluated before MeterRegistry is registered, so @ConditionalOnBean(MeterRegistry::class) fails and the whole class is skipped.

Reproduction

Minimal reproducer: Spring Boot 3.5.7 application with spring-boot-starter-actuator, micrometer-registry-prometheus, and the okapi BOM dependencies (okapi-core, okapi-postgres, okapi-http, okapi-spring-boot, okapi-micrometer).

  1. Configure a DataSource and provide an HttpMessageDeliverer bean.
  2. Start the app.
  3. curl http://localhost:8080/actuator/prometheus | grep okapi_ — empty.
  4. Try injecting MicrometerOutboxListener anywhere — Spring fails with:

    Parameter 0 of method X required a bean of type 'com.softwaremill.okapi.micrometer.MicrometerOutboxListener' that could not be found.

The condition evaluation report (--debug) shows OkapiMicrometerAutoConfiguration did not match because of @ConditionalOnBean(MeterRegistry::class), even though MeterRegistry is present in the running context.

Expected behavior

On any version of Spring Boot listed in the README compatibility matrix, OkapiMicrometerAutoConfiguration should be evaluated after the auto-configuration that registers MeterRegistry, so that @ConditionalOnBean(MeterRegistry::class) reliably matches.

Proposed fix

@AutoConfigureAfter(name = ...) accepts an array — list both packages so the hint is honored on either Spring Boot major version:

@AutoConfigureAfter(
    name = [
        // Spring Boot 3.5.x
        "org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration",
        // Spring Boot 4.0.x
        "org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration",
    ],
)

Spring Boot ignores missing class names per entry, so listing both is safe across versions — whichever is on the classpath wins, and the hint is honored on every supported runtime.

Workaround in the meantime

Manually register the listener in user code; ordinary @Configuration is processed after auto-configurations, so MeterRegistry is always available:

@Configuration
class OkapiWorkaroundConfig {
    @Bean
    fun micrometerOutboxListener(registry: MeterRegistry): MicrometerOutboxListener = 
        MicrometerOutboxListener(registry)
}

(Doesn't recover MicrometerOutboxMetrics/OutboxMetricsRefresher — gauges remain unavailable until the auto-config fix lands.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions