1

I'm writing a custom Spring Boot starter and need to check for certain requirements in the client application's context. I do this at @Conditional evaluation time using custom Condition classes. One of these conditions needs to check for the presence of a Postgres-connected DataSource. The problem is that I can't seem to find a way to ensure that the condition is evaluated after a DataSource is created, even though one will be available after a few seconds.

To ensure I have a viable context at @Conditional evaluation time, I used two chained auto-configuration classes: the first loads a "context validation bean," and the second performs the actual job. Like this:

@AutoConfiguration
@EnableConfigurationProperties(OutboxStarterProperties.class)
public class ContextInitAutoconfiguration {

    @Bean
    public ContextManager outboxContextRequirementValidator(
            Environment environment,
            ApplicationContext applicationContext
    ){
        return new ContextManager(environment, applicationContext);
    }
    
}

@AutoConfiguration(after = ContextInitAutoconfiguration.class)
public class OutboxStarterAutoconfiguration {
......

I tried both

@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)

and

@AutoConfiguration(after = DataSourceAutoConfiguration.class)

none of them worked.

10
  • Create an @Bean that requires a DataSource. Commented May 21, 2024 at 6:32
  • Yeah I mean I could use a combination of @ConditionalOnBean and @ConditionalOnMissingBean, but it would be more of a workaround. What I'd like to have is a single reliable entrypoint where I can be sure that the context is ready and then potentially check n conditions like: beans presence, configuration, and so on. Commented May 21, 2024 at 8:33
  • Why would that be a workaround? There is no reliable entry point because what you are doing (or want to do) is part of the context setup. You want to add beans else why would you create an auto-configuration in the first place. Commented May 21, 2024 at 8:36
  • Can you iterate what you want to achieve (your usecase) not your technical solution ? It feels like you are using the wrong solution for your problem, but you haven't described the actual problem you are trying to solve (only the technical roadblock you are running into). Commented May 21, 2024 at 9:05
  • The project is a starter that implements a transactional outbox. To get it working smoothly, I need to perform several checks as I mentioned before. It would be easier to understand by reading the code: github.com/thestroke82/outbox-starter/tree/master/… Commented May 21, 2024 at 9:11

1 Answer 1

0

Solution:

After some digging I found: ConfigurationCondition (javadoc). Implementing this interface with ConfigurationPhase.REGISTER_BEAN ensures that the condition is evaluated at the right time, when the bean definitions are ready. It can be used as follows:

@Bean
@Conditional({
    StarterEnabled.class,
    ContextValidCondition.class
})
@ConditionalOnMissingBean(TaskScheduler.class)
public TaskScheduler threadPoolTaskScheduler(){
    ThreadPoolTaskScheduler threadPoolTaskScheduler
        = new ThreadPoolTaskScheduler();
    threadPoolTaskScheduler.setPoolSize(5);
    threadPoolTaskScheduler.setThreadNamePrefix(
        "ThreadPoolTaskScheduler");
    return threadPoolTaskScheduler;
}

In this case, ContextValidCondition implements ConfigurationCondition and is able to accurately verify the presence of certain beans in the context:

public class ContextValidCondition implements ConfigurationCondition {
  @Override
  public ConfigurationPhase getConfigurationPhase() {
    return ConfigurationPhase.REGISTER_BEAN;
  }

  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    ContextRequirementsValidator validator = 
                 ContextRequirementsValidator.getInstance(context);
    return validator.validate();
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.