Исключение классов в Spring Boot из авто-конфигурации по условию

Всем привет. Я разрабатываю систему на Spring Boot и столкнулся с необходимостью при определенном значении в файле application.properties вообще не пытаться подключиться к базе данных. Значение либо true, либо false. То есть, если значение false, то мне нужно написать, что то вроде такого:

@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class,
    DataSourceTransactionManagerAutoConfiguration.class,
    HibernateJpaAutoConfiguration.class
})

И убрать эти классы из загрузки. Проблема именно в условии. Убрать базу данных из автозагрузки Spring Boot у меня получилось, но сделать условие для этого не получается. Может быть кто-то знает как решить?


Ответы (2 шт):

Автор решения: Sergey Mitrofanov

Вы выполнили первую часть задачи - отключили автоконфигурацию. Теперь надо понять, при каких условиях вам нужна БД. Это можно разрулить профайлами. Например, вы хотите работать без БД в профайле 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() { ... }

→ Ссылка
Автор решения: ulxanxv

В общем, если кому-то будет интересно как это сделать: во-первых, нужно отключить классы из автоконфигурации (через аннотацию @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, хоть там и не совсем рабочий код, но он натолкнул меня на мысли.

→ Ссылка