Hey, I have a similar problem with Springdoc and Resilience4j, @wilkinsona as #45709.

Springdoc:

@Bean
@Lazy(false)
SpringDocParameterNameDiscoverer localSpringDocParameterNameDiscoverer() {
    return new SpringDocParameterNameDiscoverer();
}

Resilience4j:

@Bean
@ConditionalOnMissingBean
public ParameterNameDiscoverer parameterNameDiscoverer() {
    return configuration.parameterNameDiscoverer();
}

The app deploys fine as a -in-development version in our development environment on cloud foundry. However, when pushing the same code to our release branch (only the version number in the pom.xml is changed — no -SNAPSHOT), the application fails with the following exception:

APPLICATION FAILED TO START
Description:

Parameter 1 of method spelResolver in io.github.resilience4j.springboot3.spelresolver.autoconfigure.SpelResolverConfigurationOnMissingBean required a single bean, but 2 were found:
- parameterNameDiscoverer: defined by method 'parameterNameDiscoverer' in class path resource [io/github/resilience4j/springboot3/spelresolver/autoconfigure/SpelResolverConfigurationOnMissingBean.class]
- localSpringDocParameterNameDiscoverer: defined by method 'localSpringDocParameterNameDiscoverer' in class path resource [org/springdoc/core/configuration/SpringDocConfiguration.class]
I would have expected that @ConditionalOnMissingBean is evaluated after all other beans are registered, so that parameterNameDiscoverer() from Resilience4j is only created if no other ParameterNameDiscoverer exists.
However, what seems to happen is that both beans are created.

Is there something I'm misunderstanding? This was never an issue in Spring Boot 3.4.6, but in 3.5.0 the behavior seems to have changed and my code is now unstable.

I can't directly control either library and will raise issues if needed for them, but in my opinion, they work together correctly. I just want to clarify this behavior first, might it be a spring boot 3.5.0 issue?

Comment From: wilkinsona

For @ConditionalOnMissingBean to work in this case the configuration class that defines parameterNameDiscoverer must be parsed after the configuration class that defines localSpringDocParameterNameDiscoverer.

  • If they're both auto-configuration classes (or both imported by auto-configuration classes), that can be achieved using auto-configuration ordering. In the absence of any ordering, auto-configuration classes are ordered alphabetically. As such the ordering of two auto-configuration classes and everything they import should always be deterministic.
  • If one's a standard configuration class and the other's an auto-configuration class, the standard configuration class will always be parsed first.
  • If they're both user configuration classes found, for example, by component scanning, the ordering won't be well defined and you may see problems like this.

There isn't enough context in this issue to tell which of these three options applies here. My guess would be that the code has always been potentially unstable and something else has shaken loose a long-standing bug.

If you can share a minimal sample that combines both Resilience4j and SpringDoc way may be able to identify where the potential instability is coming from.

Comment From: Nico-Strecker

I will check that tomorrow and inform you and i try to set up a similar example but it just happens sometimes i dont know the exact reason either