Рубрики
Без рубрики

Создайте пользовательскую автоматическую конфигурацию с помощью Spring Boot

Краткое практическое руководство по созданию пользовательской автоматической конфигурации в Spring Boot.

Автор оригинала: baeldung.

1. Обзор

Проще говоря, автоконфигурация загрузки Spring представляет собой способ автоматической настройки приложения Spring на основе зависимостей, присутствующих в пути к классам.

Это может ускорить и упростить разработку, устраняя необходимость в определении определенных компонентов, включенных в классы автоматической конфигурации.

В следующем разделе мы рассмотрим создание нашей пользовательской автоматической конфигурации Spring Boot .

2. Зависимости Maven

Давайте начнем с зависимостей, которые нам нужны:


    org.springframework.boot
    spring-boot-starter-data-jpa
    2.4.0


    mysql
    mysql-connector-java
    8.0.19

Последние версии spring-boot-starter-data-jpa и mysql-connector-java можно загрузить с Maven Central.

3. Создание пользовательской автоматической конфигурации

Чтобы создать пользовательскую автоконфигурацию, нам нужно создать класс с аннотацией @Конфигурация и зарегистрируйте его.

Давайте создадим пользовательскую конфигурацию для источника данных MySQL :

@Configuration
public class MySQLAutoconfiguration {
    //...
}

Следующим обязательным шагом является регистрация класса в качестве кандидата на автоматическую настройку, добавив имя класса под ключом org.springframework.boot.autoconfigure.EnableAutoConfiguration в стандартном файле ресурсы/META-INF/spring.factories :

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baeldung.autoconfiguration.MySQLAutoconfiguration

Если мы хотим, чтобы наш класс автоконфигурации имел приоритет над другими кандидатами на автоконфигурацию, мы можем добавить @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) аннотация.

Автоконфигурация разрабатывается с использованием классов и компонентов, помеченных аннотациями @Conditional , чтобы можно было заменить автоконфигурацию или отдельные ее части.

Обратите внимание, что автоматическая настройка действует только в том случае, если автоматически настроенные компоненты не определены в приложении. Если вы определяете свой боб, то по умолчанию он будет переопределен.

3.1. Условия класса

Условия класса позволяют нам указать, что компонент конфигурации будет включен, если указанный класс присутствует с помощью @ConditionalOnClass аннотации, или если класс отсутствует с помощью @ConditionalOnMissingClass аннотации.

Давайте уточним, что ваша конфигурация MySQL будет загружена только в том случае, если присутствует класс Источник данных , и в этом случае мы можем предположить, что приложение будет использовать базу данных:

@Configuration
@ConditionalOnClass(DataSource.class)
public class MySQLAutoconfiguration {
    //...
}

3.2. Условия использования бобов

Если мы хотим включить компонент только в том случае , если указанный компонент присутствует или отсутствует , мы можем использовать аннотации @ConditionalOnBean и @ConditionalOnMissingBean .

Чтобы проиллюстрировать это, давайте добавим компонент EntityManagerFactory в наш класс конфигурации и укажем, что мы хотим, чтобы этот компонент создавался только в том случае, если присутствует компонент с именем DataSource и если компонент с именем EntityManagerFactory еще не определен:

@Bean
@ConditionalOnBean(name = "dataSource")
@ConditionalOnMissingBean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean em
      = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource());
    em.setPackagesToScan("com.baeldung.autoconfiguration.example");
    em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    if (additionalProperties() != null) {
        em.setJpaProperties(additionalProperties());
    }
    return em;
}

Давайте также настроим компонент transaction Manager , который будет загружаться только в том случае, если компонент типа JpaTransactionManager еще не определен:

@Bean
@ConditionalOnMissingBean(type = "JpaTransactionManager")
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    return transactionManager;
}

3.3. Условия Собственности

Аннотация @ConditionalOnProperty используется для указания, будет ли загружена конфигурация на основе наличия и значения свойства среды Spring .

Во-первых, давайте добавим исходный файл свойств для нашей конфигурации, который определит, откуда будут считываться свойства:

@PropertySource("classpath:mysql.properties")
public class MySQLAutoconfiguration {
    //...
}

Мы можем настроить основной источник данных компонент, который будет использоваться для создания подключений к базе данных, таким образом, чтобы он загружался только при наличии свойства usemysql .

Мы можем использовать атрибут имеющий значение для указания определенных значений свойства usemysql , которые должны быть сопоставлены.

Давайте определим Источник данных bean со значениями по умолчанию, которые подключаются к локальной базе данных с именем myDb , если для свойства user mysql установлено значение local :

@Bean
@ConditionalOnProperty(
  name = "usemysql", 
  havingValue = "local")
@ConditionalOnMissingBean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
 
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true");
    dataSource.setUsername("mysqluser");
    dataSource.setPassword("mysqlpass");

    return dataSource;
}

Если для свойства user mysql установлено значение custom, Источник данных компонент будет настроен с использованием значений пользовательских свойств для URL-адреса базы данных, пользователя и пароля:

@Bean(name = "dataSource")
@ConditionalOnProperty(
  name = "usemysql", 
  havingValue = "custom")
@ConditionalOnMissingBean
public DataSource dataSource2() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
        
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl(env.getProperty("mysql.url"));
    dataSource.setUsername(env.getProperty("mysql.user") != null 
      ? env.getProperty("mysql.user") : "");
    dataSource.setPassword(env.getProperty("mysql.pass") != null 
      ? env.getProperty("mysql.pass") : "");
        
    return dataSource;
}

Файл mysql.properties будет содержать свойство use mysql :

usemysql=local

Если приложение, использующее MySQLAutoconfiguration , хочет переопределить свойства по умолчанию, все, что ему нужно сделать, это добавить различные значения для mysql.url , mysql.user и mysql.pass properties и usemysql=custom строки в файле mysql.properties .

3.4. Ресурсные условия

Добавление аннотации @Conditionaldatasource означает, что конфигурация будет загружена только при наличии указанного ресурса .

Давайте определим метод с именем additional Properties () , который будет возвращать объект Properties , содержащий свойства, специфичные для гибернации, которые будут использоваться EntityManagerFactory bean, только если файл ресурсов mysql.properties присутствует:

@ConditionalOnResource(
  resources = "classpath:mysql.properties")
@Conditional(HibernateCondition.class)
Properties additionalProperties() {
    Properties hibernateProperties = new Properties();

    hibernateProperties.setProperty("hibernate.hbm2ddl.auto", 
      env.getProperty("mysql-hibernate.hbm2ddl.auto"));
    hibernateProperties.setProperty("hibernate.dialect", 
      env.getProperty("mysql-hibernate.dialect"));
    hibernateProperties.setProperty("hibernate.show_sql", 
      env.getProperty("mysql-hibernate.show_sql") != null 
      ? env.getProperty("mysql-hibernate.show_sql") : "false");
    return hibernateProperties;
}

Мы можем добавить определенные свойства Hibernate в файл mysql.properties :

mysql-hibernate.dialect=org.hibernate.dialect.MySQLDialect
mysql-hibernate.show_sql=true
mysql-hibernate.hbm2ddl.auto=create-drop

3.5. Пользовательские условия

Если мы не хотим использовать какие-либо условия, доступные в Spring Boot, мы также можем определить пользовательские условия, расширив класс SpringBootCondition и переопределив метод getMatchOutcome () .

Давайте создадим условие под названием Hibernate Condition для нашего дополнительного свойства() метода, который проверит, является ли HibernateEntityManager класс присутствует в пути к классу:

static class HibernateCondition extends SpringBootCondition {

    private static String[] CLASS_NAMES
      = { "org.hibernate.ejb.HibernateEntityManager", 
          "org.hibernate.jpa.HibernateEntityManager" };

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, 
      AnnotatedTypeMetadata metadata) {
 
        ConditionMessage.Builder message
          = ConditionMessage.forCondition("Hibernate");
        return Arrays.stream(CLASS_NAMES)
          .filter(className -> ClassUtils.isPresent(className, context.getClassLoader()))
          .map(className -> ConditionOutcome
            .match(message.found("class")
            .items(Style.NORMAL, className)))
          .findAny()
          .orElseGet(() -> ConditionOutcome
            .noMatch(message.didNotFind("class", "classes")
            .items(Style.NORMAL, Arrays.asList(CLASS_NAMES))));
    }
}

Затем мы можем добавить условие в метод дополнительные свойства() :

@Conditional(HibernateCondition.class)
Properties additionalProperties() {
  //...
}

3.6. Условия применения

Мы также можем указать , что конфигурация может быть загружена только внутри/вне веб-контекста , добавив аннотацию @ConditionalOnWebApplication или @ConditionalOnNotWebApplication .

4. Тестирование автоматической настройки

Давайте создадим очень простой пример для проверки нашей автоматической конфигурации. Мы создадим класс сущностей с именем MyUser и интерфейс My UserRepository с использованием данных Spring:

@Entity
public class MyUser {
    @Id
    private String email;

    // standard constructor, getters, setters
}
public interface MyUserRepository 
  extends JpaRepository { }

Чтобы включить автоматическую настройку, мы можем использовать одну из @SpringBootApplication или @EnableAutoConfiguration аннотаций:

@SpringBootApplication
public class AutoconfigurationApplication {
    public static void main(String[] args) {
        SpringApplication.run(AutoconfigurationApplication.class, args);
    }
}

Далее, давайте напишем тест JUnit , который сохранит сущность MyUser :

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(
  classes = AutoconfigurationApplication.class)
@EnableJpaRepositories(
  basePackages = { "com.baeldung.autoconfiguration.example" })
public class AutoconfigurationTest {

    @Autowired
    private MyUserRepository userRepository;

    @Test
    public void whenSaveUser_thenOk() {
        MyUser user = new MyUser("[email protected]");
        userRepository.save(user);
    }
}

Поскольку мы не определили нашу конфигурацию источника данных|/, приложение будет использовать созданную нами автоматическую конфигурацию для подключения к базе данных MySQL с именем myDb .

Строка подключения содержит createDatabaseIfNotExist=true свойство, поэтому база данных не должна существовать. Однако пользователь пользователь mysql или тот, который указан через или тот, который указан через свойство, если оно присутствует, должно быть создано.

Мы можем проверить журнал приложений, чтобы увидеть, что используется источник данных MySQL :

web - 2017-04-12 00:01:33,956 [main] INFO  o.s.j.d.DriverManagerDataSource - Loaded JDBC driver: com.mysql.cj.jdbc.Driver

5. Отключение Классов Автоматической настройки

Если бы мы хотели исключить автоматическую конфигурацию из загрузки , мы могли бы добавить @EnableAutoConfiguration аннотацию с атрибутом exclude или excludeName в класс конфигурации:

@Configuration
@EnableAutoConfiguration(
  exclude={MySQLAutoconfiguration.class})
public class AutoconfigurationApplication {
    //...
}

Другой вариант отключения определенных автоконфигураций-это установка свойства spring.auto configure.exclude :

spring.autoconfigure.exclude=com.baeldung.autoconfiguration.MySQLAutoconfiguration

6. Выводы

В этом уроке мы показали, как создать пользовательскую автоматическую конфигурацию Spring Boot. Полный исходный код примера можно найти на GitHub .

Тест JUnit можно запустить с помощью auto configuration profile: mvn clean install -Autoconfiguration .