1. 概述
依賴管理是任何複雜項目的關鍵組成部分。手動進行依賴管理效率低下;您花費在其中的時間越多,您在項目其他重要方面的時間就越少。
Spring Boot Starter 旨在解決這個問題。Starter POM 是一組便捷的依賴描述符,您可以將其包含在您的應用程序中。您將獲得一個一站式解決方案,用於所有您需要的 Spring 和相關技術,而無需在示例代碼中搜索並複製粘貼大量的依賴描述符。
我們擁有超過 30 個 Boot Starter 可供選擇 – 在後續部分中我們將一一介紹。
2. Web Starter
首先,讓我們看看如何開發 REST 服務;我們可以使用像 Spring MVC、Tomcat 和 Jackson 這樣的庫——對於單個應用程序來説,依賴項很多。
Spring Boot Starter 可以通過添加單個依賴項來減少手動添加依賴項的數量。因此,與其手動指定依賴項,不如像下面的示例一樣添加一個 Starter:
<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 是一個簡單的 Bean,其 類型為 , 類型為 。
這就是全部——應用程序運行後,您可以通過訪問 http://localhost:8080/entity/all 並檢查控制器是否正常工作。
我們創建了一個配置相當精簡的 REST 應用程序。
3. 測試啓動器
為了進行測試,我們通常使用以下庫集:Spring Test、JUnit、Hamcrest 和 Mockito。我們可以手動包含所有這些庫,但 Spring Boot 啓動器可以用來自動包含這些庫,具體方法如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>請注意,您無需指定 Artifact 的版本號。Spring Boot 會自動確定使用哪個版本——您只需要指定 spring-boot-starter-parent Artifact 的版本即可。如果稍後您需要升級 Boot 庫和依賴項,只需在一個地方升級 Boot 版本,它會自動處理其餘部分。
現在,讓我們實際測試我們在上一示例中創建的控制器。
測試控制器有兩方便:
- 使用 Mock 環境
- 使用嵌入式 Servlet 容器(如 Tomcat 或 Jetty)
在此示例中,我們將使用 Mock 環境。
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Application.class)
@WebAppConfiguration
public class SpringBootApplicationIntegrationTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@BeforeEach
public void setupMockMvc() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void givenRequestHasBeenMade_whenMeetsAllOfGivenConditions_thenCorrect()
throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/entity/all"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.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"));
}
//...
}重要的是,<i data-san="@WebAppConfiguration"></i>註解和<i data-san="MockMVC"></i>是<i data-san="spring-test"></i>模塊的一部分,<i data-san="hasSize"></i>是一個 Hamcrest 匹配器,<i data-san="@BeforeEach"></i>是一個 JUnit 註解。 這些都可通過導入一個 starter 依賴項提供。
4. 數據 JPA 啓動器
大多數 Web 應用程序都有某種持久化機制,而 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 測試:
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Application.class)
public class SpringBootJPAIntegrationTest {
@Autowired
private GenericEntityRepository genericEntityRepository;
@Test
public void givenGenericEntityRepository_whenSaveAndRetreiveEntity_thenOK() {
GenericEntity genericEntity = genericEntityRepository.save(new GenericEntity("test"));
GenericEntity foundEntity = genericEntityRepository.findById(genericEntity.getId()).orElse(null);
assertNotNull(foundEntity);
assertEquals(genericEntity.getValue(), foundEntity.getValue());
}
}我們沒有花費時間來指定數據庫供應商、URL 連接以及憑據。由於我們受益於 Boot 的強大默認設置,因此不需要進行額外的配置;當然,如果需要,所有這些細節仍然可以進行配置。
5. Mail Starter
在企業開發中,發送電子郵件是一個非常常見的任務,直接處理 Java Mail API 通常會比較困難。
Spring Boot starter 隱藏了這種複雜性 – 可以通過以下方式指定 mail 依賴項:
<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 中央倉庫 中找到。
以下是測試代碼:
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Application.class)
public class SpringBootMailIntegrationTest {
@Autowired
private JavaMailSender javaMailSender;
private Wiser wiser;
private final String userTo = "user2@localhost";
private final String userFrom = "user1@localhost";
private final String subject = "Test subject";
private final String textMail = "Text subject mail";
@BeforeEach
public void setUp() {
final int TEST_PORT = 8025;
wiser = Wiser.port(TEST_PORT);
wiser.start();
}
@AfterEach
public void tearDown() {
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;
}
}
在測試中,@BeforeEach 和 @AfterEach 方法負責啓動和停止郵件服務器。
請注意,我們正在配置 JavaMailSender Bean – 該 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 Starters 的主要優勢:
- 提高 POM 包可管理性
- 提供生產級、經過測試和支持的依賴配置
- 減少項目整體配置時間