Перейти к основному содержимому

Введение в Spring Boot Starters

· 6 мин. чтения

Задача: Медиана двух отсортированных массивов

Даны два отсортированных массива размерами n и m. Найдите медиану слияния этих двух массивов.
Временная сложность решения должна быть O(log(m + n)) ...

ANDROMEDA

1. Обзор

Управление зависимостями является критическим аспектом любого сложного проекта. И делать это вручную далеко не идеально; чем больше времени вы потратили на это, тем меньше у вас осталось времени на другие важные аспекты проекта.

Стартеры Spring Boot были созданы именно для решения этой проблемы. Стартовые POM — это набор удобных дескрипторов зависимостей, которые вы можете включить в свое приложение. Вы получаете универсальный магазин для всех необходимых вам Spring и сопутствующих технологий, без необходимости искать примеры кода и копировать и вставлять множество дескрипторов зависимостей.

У нас есть более 30 загрузчиков — давайте рассмотрим некоторые из них в следующих разделах.

2. Веб-стартер

Во-первых, давайте рассмотрим разработку службы REST; мы можем использовать такие библиотеки, как Spring MVC, Tomcat и Jackson — множество зависимостей для одного приложения.

Стартеры Spring Boot могут помочь уменьшить количество добавляемых вручную зависимостей, просто добавив одну зависимость. Поэтому вместо того, чтобы вручную указывать зависимости, просто добавьте один стартер, как в следующем примере:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Теперь мы можем создать REST-контроллер. Для простоты мы не будем использовать базу данных и сосредоточимся на контроллере REST:

@RestController
public class GenericEntityController {
private List<GenericEntity> entityList = new ArrayList<>();

@RequestMapping("/entity/all")
public List<GenericEntity> findAll() {
return entityList;
}

@RequestMapping(value = "/entity", method = RequestMethod.POST)
public GenericEntity addEntity(GenericEntity entity) {
entityList.add(entity);
return entity;
}

@RequestMapping("/entity/findby/{id}")
public GenericEntity findById(@PathVariable Long id) {
return entityList.stream().
filter(entity -> entity.getId().equals(id)).
findFirst().get();
}
}

GenericEntity — это простой компонент с идентификатором типа Long и значением типа String .

Вот и все — при запущенном приложении вы можете получить доступ к http://localhost:8080/entity/all и проверить, работает ли контроллер.

Мы создали приложение REST с минимальной конфигурацией.

3. Тестовый стартер

Для тестирования мы обычно используем следующий набор библиотек: Spring Test, JUnit, Hamcrest и Mockito. Мы можем включить все эти библиотеки вручную, но Spring Boot starter можно использовать для автоматического включения этих библиотек следующим образом:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

Обратите внимание, что вам не нужно указывать номер версии артефакта. Spring Boot определит, какую версию использовать — все, что вам нужно указать, это версию артефакта spring-boot-starter-parent . Если позже вам понадобится обновить загрузочную библиотеку и зависимости, просто обновите загрузочную версию в одном месте, и она позаботится обо всем остальном.

Давайте на самом деле протестируем контроллер, который мы создали в предыдущем примере.

Проверить контроллер можно двумя способами:

  • Использование фиктивной среды
  • Использование встроенного контейнера сервлетов (например, Tomcat или Jetty)

В этом примере мы будем использовать фиктивную среду:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class SpringBootApplicationIntegrationTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;

@Before
public void setupMockMvc() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}

@Test
public void givenRequestHasBeenMade_whenMeetsAllOfGivenConditions_thenCorrect()
throws Exception {
MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
mockMvc.perform(MockMvcRequestBuilders.get("/entity/all")).
andExpect(MockMvcResultMatchers.status().isOk()).
andExpect(MockMvcResultMatchers.content().contentType(contentType)).
andExpect(jsonPath("$", hasSize(4)));
}
}

Приведенный выше тест вызывает конечную точку /entity/all и проверяет, что ответ JSON содержит 4 элемента. Чтобы этот тест прошел, мы также должны инициализировать наш список в классе контроллера:

public class GenericEntityController {
private List<GenericEntity> entityList = new ArrayList<>();

{
entityList.add(new GenericEntity(1l, "entity_1"));
entityList.add(new GenericEntity(2l, "entity_2"));
entityList.add(new GenericEntity(3l, "entity_3"));
entityList.add(new GenericEntity(4l, "entity_4"));
}
//...
}

Здесь важно то, что аннотация @WebAppConfiguration и MockMVC являются частью модуля весеннего тестирования , hasSize — это сопоставитель Hamcrest, а @Before — аннотация JUnit. Все они доступны путем импорта одной этой стартовой зависимости.

4. Стартер Data JPA

Большинство веб-приложений имеют своего рода постоянство — и это довольно часто JPA.

Вместо того, чтобы определять все связанные зависимости вручную — давайте вместо этого воспользуемся стартером:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>

Обратите внимание, что из коробки у нас есть автоматическая поддержка как минимум следующих баз данных: H2, Derby и Hsqldb. В нашем примере мы будем использовать H2.

Теперь давайте создадим репозиторий для нашей сущности:

public interface GenericEntityRepository extends JpaRepository<GenericEntity, Long> {}

Время протестировать код. Вот тест JUnit:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class SpringBootJPATest {

@Autowired
private GenericEntityRepository genericEntityRepository;

@Test
public void givenGenericEntityRepository_whenSaveAndRetreiveEntity_thenOK() {
GenericEntity genericEntity =
genericEntityRepository.save(new GenericEntity("test"));
GenericEntity foundedEntity =
genericEntityRepository.findOne(genericEntity.getId());

assertNotNull(foundedEntity);
assertEquals(genericEntity.getValue(), foundedEntity.getValue());
}
}

Мы не тратили время на указание поставщика базы данных, URL-подключения и учетных данных. Никаких дополнительных настроек не требуется, так как мы пользуемся фиксированными настройками загрузки по умолчанию; но, конечно, все эти детали можно настроить при необходимости.

5. Почтовый стартер

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

Spring Boot starter скрывает эту сложность — почтовые зависимости можно указать следующим образом:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

Теперь мы можем напрямую использовать JavaMailSender , так что давайте напишем несколько тестов.

Для тестирования нам понадобится простой SMTP-сервер. В этом примере мы будем использовать Wiser. Вот как мы можем включить его в наш POM:

<dependency>
<groupId>org.subethamail</groupId>
<artifactId>subethasmtp</artifactId>
<version>3.1.7</version>
<scope>test</scope>
</dependency>

Последнюю версию Wiser можно найти в центральном репозитории Maven .

Вот исходный код теста:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class SpringBootMailTest {
@Autowired
private JavaMailSender javaMailSender;

private Wiser wiser;

private String userTo = "user2@localhost";
private String userFrom = "user1@localhost";
private String subject = "Test subject";
private String textMail = "Text subject mail";

@Before
public void setUp() throws Exception {
final int TEST_PORT = 25;
wiser = new Wiser(TEST_PORT);
wiser.start();
}

@After
public void tearDown() throws Exception {
wiser.stop();
}

@Test
public void givenMail_whenSendAndReceived_thenCorrect() throws Exception {
SimpleMailMessage message = composeEmailMessage();
javaMailSender.send(message);
List<WiserMessage> messages = wiser.getMessages();

assertThat(messages, hasSize(1));
WiserMessage wiserMessage = messages.get(0);
assertEquals(userFrom, wiserMessage.getEnvelopeSender());
assertEquals(userTo, wiserMessage.getEnvelopeReceiver());
assertEquals(subject, getSubject(wiserMessage));
assertEquals(textMail, getMessage(wiserMessage));
}

private String getMessage(WiserMessage wiserMessage)
throws MessagingException, IOException {
return wiserMessage.getMimeMessage().getContent().toString().trim();
}

private String getSubject(WiserMessage wiserMessage) throws MessagingException {
return wiserMessage.getMimeMessage().getSubject();
}

private SimpleMailMessage composeEmailMessage() {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setTo(userTo);
mailMessage.setReplyTo(userFrom);
mailMessage.setFrom(userFrom);
mailMessage.setSubject(subject);
mailMessage.setText(textMail);
return mailMessage;
}
}

В тесте методы @Before и @After отвечают за запуск и остановку почтового сервера.

Обратите внимание, что мы подключаем bean-компонент JavaMailSender — bean-компонент был автоматически создан Spring Boot .

Как и любые другие значения по умолчанию в Boot, параметры электронной почты для JavaMailSender можно настроить в application.properties :

spring.mail.host=localhost
spring.mail.port=25
spring.mail.properties.mail.smtp.auth=false

Итак, мы настроили почтовый сервер на localhost:25 и не требовали аутентификации.

6. Заключение

В этой статье мы дали обзор Starters, объяснили, зачем они нам нужны, и привели примеры того, как их использовать в ваших проектах.

Давайте вспомним преимущества использования стартеров Spring Boot:

  • повысить управляемость помпонами
  • готовые к производству, протестированные и поддерживаемые конфигурации зависимостей
  • сократить общее время настройки проекта

Актуальный список стартеров можно посмотреть здесь . Исходный код для примеров можно найти здесь .