Исключение классов в Spring Boot из авто-конфигурации по условию
Всем привет. Я разрабатываю систему на Spring Boot и столкнулся с необходимостью при определенном значении в файле application.properties вообще не пытаться подключиться к базе данных. Значение либо true, либо false. То есть, если значение false, то мне нужно написать, что то вроде такого:
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
И убрать эти классы из загрузки. Проблема именно в условии. Убрать базу данных из автозагрузки Spring Boot у меня получилось, но сделать условие для этого не получается. Может быть кто-то знает как решить?
Ответы (2 шт):
Вы выполнили первую часть задачи - отключили автоконфигурацию. Теперь надо понять, при каких условиях вам нужна БД. Это можно разрулить профайлами. Например, вы хотите работать без БД в профайле dev, а в остальных вариациях работать с базой.
Вам необходимо создать бин, который будет поднимать бин с конфигурацией только в том, случае, когда ваш профайл отличается от dev
@Configuration
public class DbConfiguration {
@Bean
@Profile("!dev")
public DataSource getDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
return dataSourceBuilder.build();
}
}
Что бы указать, какой профайл сейчас используется - при запуске используем ключ -Dspring.profiles.active=dev или переменную окружения SPRING_PROFILES_ACTIVE=dev.
Если брать свойство из файла конфигурации принципиально, то следует заменить @Profile на @ConditionalOnProperty.
@Bean
@ConditionalOnProperty(
value="app.dtatbase.enabled",
havingValue = "true",
matchIfMissing = true)
public DataSource getDataSource() { ... }
В общем, если кому-то будет интересно как это сделать: во-первых, нужно отключить классы из автоконфигурации (через аннотацию @SpringBootApplication и в ней exclude), как я и сделал изначально, а затем написать нечто такое:
@Slf4j
@Configuration
@RequiredArgsConstructor
public class DbConfiguration {
private final Environment environment;
@Bean
@ConditionalOnProperty(value = "stubs.storage.database", havingValue = "true")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(this.dataSource());
em.setJpaProperties(this.getJpaProperties());
em.setPackagesToScan("...");
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return em;
}
@Bean
@ConditionalOnProperty(value = "stubs.storage.database", havingValue = "true")
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
private DataSource dataSource() {
return DataSourceBuilder.create()
.url(environment.getProperty("spring.datasource.url"))
.username(environment.getProperty("spring.datasource.username"))
.password(environment.getProperty("spring.datasource.password"))
.driverClassName(environment.getProperty("spring.datasource.driverClassName"))
.build();
}
private Properties getJpaProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", environment.getProperty("spring.jpa.hibernate.ddl-auto"));
return properties;
}
}
Здесь мы внедряем нужные для базы данных бины — entityManagerFactory, transactionManager и задаем dataSource (он внедряется в entityManagerFactory), а с помощью аннотации @ConditionalOnProperty можно задать условие создание таких бинов — как раз то что нужно.
В итоге, если в файлах конфига будет false — классы из автоконфигурации будут удалены из-за exclude в @SpringBootApplication, а эти бины не создадутся, так как не пройдут условия. Если будет true, то классы по-прежнему будут удалены из автоконфигурации, но сами условия в бинах уже пройдут и мы, можно сказать, сами сконфигурировали работу с бд — они будут добавлены в контекст и можно полноценно пользоваться базой данных.
Через класс Environment можно полазить в конфига и достать от туда нужны настройки, потому что при ручной конфигурации Spring не достает настройки для базы данных из конфигов.
P.S. Спасибо Sergey Mitrofanov, хоть там и не совсем рабочий код, но он натолкнул меня на мысли.