1. 概述
在复杂的项目中,依赖管理是关键环节。手动进行这项工作并不理想,你花在它上面的时间越多,用于项目其他重要部分的时间就越少。
Spring Boot启动器正是为了解决这个问题而设计的。启动器POM集合提供了一组方便的依赖描述符,可以直接包含在你的应用中。这样,你无需在示例代码中四处寻找并复制大量的依赖描述,就能一站式获取所有需要的Spring及相关技术。
我们有超过30个Boot启动器可供选择,接下来我们会分几节介绍一些。
2. Web启动器
首先,我们来看看如何开发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
是一个简单的bean,具有类型为Long
的id
和类型为String
的value
。
就这样——应用运行后,可以通过访问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>
注意,你不需要指定依赖的具体版本。Spring Boot会自动决定使用哪个版本——你只需要指定spring-boot-starter-parent
的版本。如果后期需要升级Boot库和依赖,只需在一个地方更新Boot版本,其余的它会自动处理。
让我们实际测试上一节创建的控制器。
测试控制器有两种方法:
- 使用模拟环境
- 使用嵌入式Servlet容器(如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
都属于spring-test
模块,hasSize
是Hamcrest匹配器,@Before
是JUnit注解。这些全都在导入一个启动器依赖时可用。
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和Hsqlldb等数据库的自动支持。在这个例子中,我们将使用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连接和凭据。由于得益于Spring Boot的坚实默认设置,我们无需额外配置;当然,如果必要,这些细节仍然可以自定义。
5. 邮件启动器
在企业开发中,发送电子邮件是一项非常常见的任务,直接处理Java Mail API通常会很复杂。
Spring Boot启动器隐藏了这种复杂性,邮件依赖可以通过以下方式指定:
<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
方法负责启动和停止邮件服务器。
请注意,我们正在将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. 总结
在这篇文章中,我们概述了启动器的功能,解释了为什么需要它们,并提供了如何在项目中使用它们的例子。
让我们总结一下使用Spring Boot启动器的好处:
- 提高
pom.xml
的管理性 - 生产就绪的、经过测试和支持的依赖配置
- 减少项目的整体配置时间