Spring Boot предоставляет стартеры для большинства популярных проектов с открытым исходным кодом, но мы не ограничиваемся ими.
Можно написать собственные стартеры. Если есть внутренняя библиотека для использования в организации, было бы неплохо написать для нее стартер, если он будет использоваться в контексте Spring Boot.
Эти стартеры позволяют разработчикам избежать длительной настройки и быстро приступить к разработке. Однако из-за того, что в фоновом режиме происходит множество вещей, иногда трудно понять, как аннотация или просто включение зависимости в pom.xml позволяет использовать так много функций.
В этой статье рассмотрим, что происходит за кулисами Spring Boot и создадим стартер для собственной пользовательской библиотеки.
Автоконфигурации Spring Boot
Классы автоматической настройки
Когда Spring Boot запускается, он ищет файл с именем spring.factories в пути к классам. Этот файл находится в каталоге META-INF. Посмотрим на фрагмент этого файла из проекта spring-boot-autoconfigure:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
Этот файл сопоставляет имя с различными классами конфигурации, которые Spring Boot попытается запустить. Согласно этому фрагменту, Spring Boot попытается запустить все классы конфигурации для RabbitMQ, Cassandra, MongoDB и Hibernate.
Будут ли эти классы работать на самом деле, зависит от наличия зависимых классов в пути к классам. Например, если классы для MongoDB будут найдены в пути к классам, запустится MongoAutoConfiguration и будут инициализированы все бины, связанные с mongo.
Эта условная инициализация включается аннотацией @ConditionalOnClass. Посмотрим на фрагмент кода из класса MongoAutoConfiguration, чтобы увидеть его использование:
@Configuration
@ConditionalOnClass(MongoClient.class)
@EnableConfigurationProperties(MongoProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
public class MongoAutoConfiguration {
// configuration code
}
Если MongoClient доступен в пути к классам, то этот класс конфигурации будет запускаться, заполняя фабрику бинов Spring с помощью MongoClient, инициализированным с настройками конфигурации по умолчанию.
Пользовательские свойства из файла application.properties
Spring Boot инициализирует бины, используя предварительно настроенные значения по умолчанию. Чтобы переопределить эти значения, обычно объявлют их в файле application.properties с определенным именем. Эти свойства автоматически подхватываются контейнером Spring Boot.
Посмотрим, как это работает.
Во фрагменте кода для MongoAutoConfiguration аннотация @EnableConfigurationProperties объявлена с классом MongoProperties, который действует как контейнер для пользовательских свойств:
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {
private String host;
// другие поля со стандартными геттерами и сеттерами
}
Префикс плюс имя поля составляют имена свойств в файле application.properties. Чтобы установить хост для MongoDB, нужно всего лишь написать в файле свойств следующее:
spring.data.mongodb.host = localhost
Точно так же значения для других полей в классе могут быть установлены с помощью файла свойств.
Создание пользовательского стартера
Основываясь на концепциях, изложенных выше, для создания пользовательского стартера необходимо написать следующие компоненты:
- класс автоматической настройки для нашей библиотеки вместе с классом свойств для пользовательской конфигурации;
- стартовый pom для ввода зависимостей библиотеки и проекта автоконфигурации.
Для демонстрации создадим простую библиотеку приветствий, которая принимает приветственное сообщение для разного времени суток в качестве параметров конфигурации и выводит приветственное сообщение. Также создадим пример приложения Spring Boot, чтобы продемонстрировать использование наших модулей автонастройки и запуска.
Модуль автоконфигурации
Назовем модуль автоматической настройки greeter-spring-boot-autoconfigure. Этот модуль будет иметь два основных класса: GreeterProperties, который позволит задавать пользовательские свойства через файл application.properties, и GreeterAutoConfiguartion, который создаст бины для библиотеки greeter.
Посмотрим на код для обоих классов:
@ConfigurationProperties(prefix = "baeldung.greeter")
public class GreeterProperties {
private String userName;
private String morningMessage;
private String afternoonMessage;
private String eveningMessage;
private String nightMessage;
// standard getters and setters
}
@Configuration
@ConditionalOnClass(Greeter.class)
@EnableConfigurationProperties(GreeterProperties.class)
public class GreeterAutoConfiguration {
@Autowired
private GreeterProperties greeterProperties;
@Bean
@ConditionalOnMissingBean
public GreetingConfig greeterConfig() {
String userName = greeterProperties.getUserName() == null
? System.getProperty("user.name")
: greeterProperties.getUserName();
// ..
GreetingConfig greetingConfig = new GreetingConfig();
greetingConfig.put(USER_NAME, userName);
// ...
return greetingConfig;
}
@Bean
@ConditionalOnMissingBean
public Greeter greeter(GreetingConfig greetingConfig) {
return new Greeter(greetingConfig);
}
}
Также нужно добавить файл spring.factories в каталог src/main/resources/META-INF со следующим содержимым:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baeldung.greeter.autoconfigure.GreeterAutoConfiguration
При запуске приложения будет запущен класс GreeterAutoConfiguration, если класс Greeter присутствует в пути к классам. В случае успешного запуска он заполнит контекст приложения Spring компонентами GreeterConfig и Greeter, прочитав свойства через класс GreeterProperties.
Аннотация @ConditionalOnMissingBean гарантирует, что эти бины будут созданы только в том случае, если они еще не существуют. Это позволяет разработчикам полностью переопределить автоматически настроенные бины, определив собственные в одном из классов @Configuration.
Создание pom.xml
Теперь создадим стартовый pom, который будет включать зависимости для модуля автоматической настройки и библиотеки приветствия.
Согласно соглашению об именах, все стартеры, которыми не управляет Spring Boot, должны начинаться с имени библиотеки, за которым следует суффикс -spring-boot-starter. Поэтому назовем наш стартер greeter-spring-boot-starter:
<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>greeter-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<greeter.version>0.0.1-SNAPSHOT</greeter.version>
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>com.baeldung</groupId>
<artifactId>greeter-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.baeldung</groupId>
<artifactId>greeter</artifactId>
<version>${greeter.version}</version>
</dependency>
</dependencies>
</project>
Использование стартера
Создадим приложение greeter-spring-boot-sample-app, которое будет использовать стартер. В pom.xml нужно добавить его как зависимость:
<dependency>
<groupId>com.baeldung</groupId>
<artifactId>greeter-spring-boot-starter</artifactId>
<version>${greeter-starter.version}</version>
</dependency>
Spring Boot автоматически все настроит, и у нас будет готовый бин Greeter для внедрения и использования.
Теперь изменим некоторые значения GreeterProperties по умолчанию, определив их в файле application.properties с префиксом baeldung.greeter:
baeldung.greeter.userName=Baeldung
baeldung.greeter.afternoonMessage=Woha\ Afternoon
Наконец, воспользуемся бином Greeter:
@SpringBootApplication
public class GreeterSampleApplication implements CommandLineRunner {
@Autowired
private Greeter greeter;
public static void main(String[] args) {
SpringApplication.run(GreeterSampleApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
String message = greeter.greet();
System.out.println(message);
}
}
Заключение
В этом кратком руководстве мы сосредоточились на развертывании пользовательского стартера Spring Boot и на том, как эти стартеры вместе с механизмом автонастройки работают в фоновом режиме, чтобы исключить большую часть ручной настройки.
Исходный код всех модулей можно найти на GitHub.