| June 15, 2022
Что вообще такое starter в Spring framework?
Допустим, Вы разрабатываете несколько приложений или микросервисов на Java. Каждое из них уникальное, и содержит свою собственную бизнес логику. Однако, в каждом из них может быть необходимость использовать общую логику. Например, логику аутентификации, как это часто бывает в мире микросервисов.
Есть несколько способов реализовать общую логику в нескольких приложениях:
- можно реализовать общую логику в каждом из приложений
- можно вынести общую логику в отдельный компонент, который при сборке будет автоматически включён в качестве части приложения
- можно вынести общую логику в отдельную библиотеку, и подключать её как отдельную зависимость
Первый подход плох тем, что на каждое изменение в общей логике, нужно эти изменения скопировать в каждое приложение, в котором эта самая общая логика присутствует. Это слабожизнеспособный вариант для коммерческой разработки.
Второй подход часто применяется в случае, когда разработка систем ведётся в монорепозиториях. С одной стороны, это означает, что изменив общую логику, разработчику необходимо изменить и все места в системе (все микросервисы и приложения, использующие общую логику). Нужно это, чтобы система была, как минимум, в состоянии быть собранной.
Третий подход - это подход, при котором общая логика выпускается в виде отдельной подключаемой библиотеки, со своим собственным версионированием и циклом выпуска. Это самый гибкий подход, поскольку позволяет разработчикам каждого приложения или микросервиса решать вопрос об обновлении зависимости с общей логикой самостоятельно.
Так что же такое - starter’ы в Spring framework? Это и есть отдельные библиотеки, со своим циклом релиза, которые позволяют использовать фишки самого Spring’а.
Примеры starter’ов
Возможно, Вы и не задумывались, но каждый раз, когда Вы пользуетесь Spring initilzr’ом, добавляя зависимости в проект, Вы добавляете starter’ы. Например:
spring-boot-starter-web
- для работы с Spring Web и MVC- или
spring-boot-starter-test
- для возможности написания тестов с подъёмом Spring контейнера
Как создать свой starter?
Это не сложно. Достаточно придерживаться следующего алгоритма:
1. Создадим новый Maven проект
Для этого воспользуемся прелестями автогенерации Maven:
mvn archetype:generate
2. Добавим необходимые зависимости в pom.xml
Следующие строки нужно вставить в dependencies
секцию pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.6.7</version>
<optional>true</optional>
</dependency>
Зависимость объявлена в качестве опциональной, поскольку действительно используемые зависимости будут добавлены самим проектом, в котором и будет использован starter.
3. Добавим Spring конфигурацию
Под Spring конфигурацией здесь имеется ввиду класс, отмеченный аннотацией @Configuration
, в котором, необходимые составные части нашего стартера, такие как бины и properties будут описаны и проинициализированы.
Например, представим, что мы должны поддержать работу с следующими property’ями:
demo:
author: Haggy Waggy
email: demo@gmail.com
Для этого, создадим класс для работы с ними:
@ConfigurationProperties(prefix = "demo")
public class DemoProperties {
private String author;
private String email;
}
Теперь, когда у нас есть описание нужных нам property’ей в Java, мы можем создать класс автоконфигурации нашего starter’а:
@Configuration
@EnableConfigurationProperties(DemoProperties.class)
public class DemoAutoConfiguration {
@Bean
public DemoService demoService(DemoProperties properties) {
return new DemoService(properties);
}
}
И для полноты примера, вот код сервиса, который мы только что использовали в классе автоконфигурации:
public class DemoService {
private final DemoProperties properties;
@Autowired
public DemoService(DemoProperties properties) {
this.properties = properties;
}
public String generateString() {
return String.format("%s: %s", properties.getAuthor(), properties.getEmail());
}
}
4. Добавим конфигурацию starter’а
Для этого, создадим файл под названием spring.factories
в директории META-INF
, в папке с ресурсами приложения (resources
):
resources
└── META-INF
└── spring.factories
В самом файле нужно указать класс автоконфигурации, который мы создали на предыдущем шаге:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.anverbogatov.starter.demo.DemoAutoConfiguration
Сборка
Вот, собственно, и всё.
Что мы имеем в данный момент - мы имеем starter, с собственной конфигурацией, которая будет использована при добавлении starter’а в Spring проекта.
Чтобы проверить, что всё работает, давайте соберём получившийся проект командой:
mvn clean install
После сборки проекта, наш starter будет добавлен в локальный maven репозиторий и таким образом, он станет доступен для использования в локальной разработке других проектов.
Использование starter’а
Добавляем в имеющийся Spring проект зависимость на наш starter. У меня это выглядит следующим образом:
<dependency>
<groupId>org.example</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
Перекрываем property starter’а в конфигурации приложения:
demo.email=random@mail.ru
Инжектим наш DemoService demoService
в какой-либо бин приложения и пробуем вызвать метод сервиса из starter’а.
Если всё сделано правильно, сервис вернёт следующую строку:
Haggy Waggy: random@mail.ru
Заключительная часть
В данной статье мы разобрали самый простой сценарий собственного Spring starter’а. Как Вы могли заметить, процесс достаточно не сложный. Самое главное не забывать о том, что каждый starter стоит описывать в собственном пространстве - как пакетном (например, com.dreamteam.starter-demo
), так и конфигурационном: starter-demo.demo.author
. Это поможет избежать проблем, связанных с пересечением сервисов и конфигруаций между несколькими starter’ами.
Список материалов
- Сайт Spring Initlzr - на котором можно сгенерировать Spring проекты, а так же, добавить туда имеющиеся starter’ы Spring’а в удобном пользовательском интерфейсе
- Хороший список имеющихся Spring starter’ов - список не полный, но подробный