Search code examples
springspring-bootkotlinspring-repositories

Spring autoconfigurations, @ConditionalOnBean with a @Repository


I have a starter module which expose a marker interface along with some repository:

interface AwesomeRepo

...

internal interface FakeRepository: Repository<JPAStub, String>, AwesomeRepo {
    fun count(): Long
}

@Entity
class JPAStub(@Id val name: String)
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(EntityManagerFactory::class)
@AutoConfigureAfter(JpaRepositoriesAutoConfiguration::class)
@EnableJpaRepositories(basePackageClasses = [FakeRepository::class])
@EntityScan(basePackageClasses = [FakeRepository::class])
class AwesomePersistenceAutoConfiguration

In another module, I have an auto configuration which depends on the AwesomeRepo to instantiate the AwesomeApplicationService

@Configuration(proxyBeanMethods = false)
class AwesomeAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean(AwesomeRepo::class)
    fun awesomeAppService(awesomeRepo: AwesomeRepo) =
            AwesomeApplicationService(awesomeRepo)

I import both autoconfigure starters in a root project.

I observe:

  • AwesomeApplicationService cannot be instantiated because AwesomeRepo bean cannot be found

When enabling debug through debug=true:

AwesomeAutoConfiguration #awesomeAppService:
      Did not match:
         - @ConditionalOnBean (types: *****.AwesomeRepo; SearchStrategy: all) did not find any beans of type *******.AwesomeRepo(OnBeanCondition)
  • I tried adding @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) to AwesomePersistenceAutoConfiguration and @AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE) to AwesomeAutoConfiguration. It did not change the issue
  • When I remove the @ConditionOnBean(AwesomeRepo::class), the AwesomeApplicationService is correctly instantiated with the repository and everything is fine.

Why does the @ConditionOnBean(AwesomeRepo::class) does not detect the AwesomeRepo bean?

EDIT: After more trials and errors, it seems order was causing the issue, applying accepted answer worked. If someone needs to go further there is a baseline of code illustrating the issue here: https://github.com/Nimamoh/spring-autoconfigurations-conditionalonbean-with-a-repository (accepted answer is on snic-answer branch)


Solution

  • AwesomeAutoConfiguration should be ordered after AwesomePersistenceAutoConfiguration so that the bean definitions for the repositories are processed before the condition kicks in.

    There is a note in @ConditionalOnBean about this specifically:

    The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.

    You can use @AutoConfigureAfter(AwesomePersistenceAutoConfiguration.class) on AwesomeAutoConfiguration to order things properly.