Oopsguy
http://oopsguy.com

Spring Boot Starter 介绍

http://www.baeldung.com/spring-boot-starters
作者:baeldung
译者:http://oopsguy.com

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,id 类型为 LongvalueString 类型。

就这样,应用程序可以开始运行了,您可以访问 http://localhost:8080/springbootapp/entity/all 并检查控制器是否正常工作。

我们已经创建了一个配置非常少的 REST 应用程序。

3、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-artifact 的版本。如果以后您想要升级 Boot 库和依赖,只需在这个地方升级 Boot 版本即可,它将会处理其余依赖的版本信息。

让我们来测试一下之前创建的控制器。

测试控制器有两种方法:

  • 使用 mock 环境
  • 使用嵌入式 Servlet 容器(如 Tomcat 或 Jetty)

在本例中,我们将使用一个 mock 环境:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class SpringBootApplicationTest {
    @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))); 
    } 
}

@WebAppConfiguration 注解和 MockMVCspring-test 模块的一部分,hasSize 是一个 Hamcrest matcher,@Before 是一个 JUnit 注解。这些都可以通过导入这个 starter 依赖来引入。

4、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 的默认支持。但如果您需要,可以进行详细配置。

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 中央仓库http://search.maven.org/#search|ga|1|subethasmtp)中找到。

以下是测试源码:

@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 的 email 设置可以在 application.properties 中自定义:

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

我们在 localhost:25 上配置了邮件服务器,不需要进行身份验证。

6、结论

在本文中,我们介绍了 Starter,解释了为什么需要它们,并提供了如何在项目中使用它们的示例。

让我们回顾一下使用 Spring Boot starter 的好处:

  • 增强 pom 可管理性
  • 生产、测试与依赖配置支持
  • 减少项目的整体配置时间

这里https://github.com/spring-projects/spring-boot/tree/master/spring-boot-starters)可以找到相关 starter 的列表。示例源码可从这里https://github.com/eugenp/tutorials/tree/master/spring-boot)获取。

原文示例代码

https://github.com/eugenp/tutorials/tree/master/spring-boot

posted @ 2017-10-13 09:32  oopsguy  阅读(1161)  评论(1编辑  收藏  举报