介绍 Spring Boot Starter
依赖管理是任何复杂项目中的关键部分。手工实现显然是不明智的,你花时间越多,则在项目的其他重要部分时间越少。Spring Boot Starter致力于完美解决这个问题。Starter POM是包括在应用中的一组便利依赖描述。可以一站式获得所有Spring和相关技术库,无需寻找相同的代码,拷贝、粘贴需要载入的依赖描述。
Spring Boot 有超过30个Starter,本文下面介绍几个常用的Starter。
Web Starter
首先,我们看下开发Rest服务应用,需要如Spring MVC,Tomcat以及Jackson————单个应用需要的一系列依赖。
Spring Boot Starter 能帮助减少手工增加依赖量,仅需要增加一个依赖。下面请看示例:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
现在我们可以创建REST controller,为了简单,我们没有使用数据库,并聚焦REST Controller:
@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 地址,检查Controller是否正常工作。我们使用最小化的配置创建REST.
Test Starter
对应测试,我们通常使用一组库: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的版本。如果后期你需要升级Boot 库及其依赖,仅需要在一个地方升级Boot版本,剩下的交给它。下面我们测试上面的Controller。有两种方式测试Controller:
- 使用mock环境
- 使用内置Servlet容器,如tomcat 或 Jetty
下面示例使用mock环境:
@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个元素。实现下面示例数据,我们需要在Controller类中初始化list:
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的注解。通过一个starter依赖可以让这些都加载。
Data JPA Starter
大多数web应用需要不同的持久化库————最常用的是JPA,无需手工引入相关的依赖,通过使用下面starter:
<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。下面为实体创建repository:
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以及凭证,无需必要的额外配置,因为我们使用Boot的默认配置,当然这些细节有需要仍然可以配置。
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>
请看测试代码:
@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方法负责启动、停止mail服务。注意我们引入JavaMailSender bean————spring boot会自动创建。和其他缺省的Boot异议,JavaMailSender的email设置可以在application.properties中配置:
spring.mail.host=localhost
spring.mail.port=25
spring.mail.properties.mail.smtp.auth=false
这里配置mail服务器在localhost:25,并且无需认证。
总结
本文我们概要介绍了Spring Boot Starter。解释了使用的必要性并提供示例说明如何在项目中使用它们。
下面回顾下面使用Spring Boot starter的优势:
- 提高pom的可管理性
- 现成的生成、测试、运行依赖配置
- 减少项目的配置时间
实际starter列表可以在这里查找。