I want to execute a function to check the database config before anything else is initialized. However, no matter what method I used, it is always called after some other components or services, which is not ideal. Is it possible to set its priority globally to be the first component created after context initialization?
I've tried the following, and this implementation below is the closest to what I want, but still not quite--as it is executed after the Flyway database executor:
@Configuration
class DataSourceConfig(
@Value("\${spring.datasource.url}") private val databaseUrl: String
) {
init {
if (databaseUrl.lowercase().contains("jdbc:sqlite:", ignoreCase = true)) {
err.println("!!! ERROR !!!\n" +
"SQLite isn't supported in the v1 development branch yet.\n" +
"Please either switch to MariaDB or wait for the stable v1 release.\n")
exitProcess(1)
}
}
}
Here are the other options that I tried:
@PostConstruct
, executing at the same time as the option below:@Configuration
class DataSourceConfig(
private val dataSource: DataSource
) {
@PostConstruct
fun checkDataSource() {
val databaseUrl = JdbcUtils.extractDatabaseMetaData(dataSource) { it.url }
// ...
}
}
@EventListener(ApplicationReadyEvent::class)
. This executes very lately, when everything else is initialized, which is not what I want.@Configuration
class DataSourceConfig(
@Value("\${spring.datasource.url}") private val databaseUrl: String
) {
@EventListener(ApplicationReadyEvent::class)
fun checkDataSource() {
// ...
}
}
Using @EventListener(ContextRefreshedEvent::class)
. In my testing, this event wasn't called at all, and the application started without calling the check, which led to a very confusing error message.
Using the CommandLineRunner
bean, still executing when everything has already initialized.
@Configuration
class DataSourceConfig {
@Bean
fun checkDataSource(dataSource: DataSource) = CommandLineRunner {
val databaseUrl = JdbcUtils.extractDatabaseMetaData(dataSource) { it.url }
// ...
}
}
According to the documentation org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent
event may fit your requirements. It is fired as soon as environment is available and you can access it with getEnvironment()
event's method.
Note, as this event is fired at such early stage, you will not be able to catch it with @EventListener
annotated method. You will need to implement ApplicationListener<ApplicationEnvironmentPreparedEvent>
interface and register it manually in your main method. Something like this
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(App.class);
springApplication.addListeners((ApplicationListener<ApplicationEnvironmentPreparedEvent>) event -> {
ConfigurableEnvironment environment = event.getEnvironment();
//check or modify environment here
});
springApplication.run(args);
}