Intro to Spring Boot Starters – Spring Boot启动器介绍

最后修改: 2016年 7月 14日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Dependency management is a critical aspects of any complex project. And doing this manually is less than ideal; the more time you spent on it the less time you have on the other important aspects of the project.

依赖性管理是任何复杂项目的一个关键方面。而手动操作是不太理想的;你在这上面花的时间越多,你在项目的其他重要方面的时间就越少。

Spring Boot starters were built to address exactly this problem. Starter POMs are a set of convenient dependency descriptors that you can include in your application. You get a one-stop-shop for all the Spring and related technology that you need, without having to hunt through sample code and copy-paste loads of dependency descriptors.

Spring Boot启动器正是为了解决这个问题而建立的。启动器POMs是一组方便的依赖描述符,你可以将其纳入你的应用程序中。你可以一站式获得你所需要的所有Spring和相关技术,而不必翻阅样本代码和复制粘贴大量的依赖描述符。

We have more than 30 Boot starters available – let’s see some of them in the following sections.

我们有30多个Boot starters可用–让我们在下面的章节中看看其中的一些。

2. The Web Starter

2.网络启动器

First, let’s look at developing the REST service; we can use libraries like Spring MVC, Tomcat and Jackson – a lot of dependencies for a single application.

首先,我们来看看开发REST服务;我们可以使用Spring MVC、Tomcat和Jackson等库–对于一个应用程序来说,有很多依赖性。

Spring Boot starters can help to reduce the number of manually added dependencies just by adding one dependency. So instead of manually specifying the dependencies just add one starter as in the following example:

Spring Boot启动器可以帮助减少手动添加的依赖项的数量,只需添加一个依赖项。因此,无需手动指定依赖关系,只需添加一个启动器,如下例所示。

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

Now we can create a REST controller. For the sake of simplicity we won’t use the database and focus on the REST controller:

现在我们可以创建一个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();
    }
}

The GenericEntity is a simple bean with id of type Long and value of type String.

GenericEntity是一个简单的Bean,id类型为Longvalue类型为String

That’s it – with the application running, you can access http://localhost:8080/entity/all and check the controller is working.

就是这样–在应用程序运行的情况下,你可以访问http://localhost:8080/entity/all并检查控制器是否工作。

We have created a REST application with quite a minimal configuration.

我们已经创建了一个配置相当简单的REST应用程序。

3. The Test Starter

3.测试启动器

For testing we usually use the following set of libraries: Spring Test, JUnit, Hamcrest, and Mockito. We can include all of these libraries manually, but Spring Boot starter can be used to automatically include these libraries in the following way:

对于测试,我们通常使用以下一组库。Spring Test、JUnit、Hamcrest和Mockito。我们可以手动包含所有这些库,但Spring Boot starter可以用以下方式自动包含这些库。

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

Notice that you don’t need to specify the version number of an artifact. Spring Boot will figure out what version to use – all you need to specify is the version of spring-boot-starter-parent artifact. If later on you need to upgrade the Boot library and dependencies, just upgrade the Boot version in one place and it will take care of the rest.

注意,你不需要指定一个工件的版本号。Spring Boot会找出要使用的版本–你所需要指定的是spring-boot-starter-parent工件的版本。如果以后你需要升级Boot库和依赖项,只需在一个地方升级Boot版本,它就会处理剩下的事情。

Let’s actually test the controller we created in the previous example.

让我们实际测试一下我们在前面的例子中创建的控制器。

There are two ways to test the controller:

有两种方法来测试控制器。

  • Using the mock environment
  • Using the embedded Servlet container (like Tomcat or Jetty)

In this example we’ll use a mock environment:

在这个例子中,我们将使用一个模拟环境。

@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))); 
    } 
}

The above test calls the /entity/all endpoint and verifies that the JSON response contains 4 elements. For this test to pass, we also have to initialize our list in the controller class:

上述测试调用/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"));
    }
    //...
}

What is important here is that @WebAppConfiguration annotation and MockMVC are part of the spring-test module, hasSize is a Hamcrest matcher, and @Before is a JUnit annotation. These are all available by importing one this one starter dependency.

这里重要的是,@WebAppConfiguration注解和MockMVCspring-test模块的一部分,hasSize是Hamcrest匹配器,而@Before是JUnit注解。这些都可以通过导入一个这样的启动依赖来实现。

4. The Data JPA Starter

4.数据JPA启动器

Most web applications have some sort of persistence – and that’s quite often JPA.

大多数Web应用程序都有某种持久性–而这往往是JPA。

Instead of defining all of the associated dependencies manually – let’s go with the starter instead:

与其手动定义所有相关的依赖关系–不如用启动器来代替。

<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>

Notice that out of the box we have automatic support for at least the following databases: H2, Derby and Hsqldb. In our example, we’ll use H2.

请注意,开箱即用,我们至少对以下数据库有自动支持。H2、Derby和Hsqldb。在我们的例子中,我们将使用H2。

Now let’s create the repository for our entity:

现在让我们为我们的实体创建资源库。

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

Time to test the code. Here is the JUnit test:

是时候测试一下代码了。这里是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());
    }
}

We didn’t spend time on specifying the database vendor, URL connection, and credentials. No extra configuration is necessary as we’re benefiting from the solid Boot defaults; but of course all of these details can still be configured if necessary.

我们没有花时间去指定数据库供应商、URL连接和证书。没有必要进行额外的配置,因为我们受益于坚实的Boot默认值;但当然,如果有必要,仍然可以配置所有这些细节。

5. The Mail Starter

5.邮件启动器

A very common task in enterprise development is sending email, and dealing directly with Java Mail API usually can be difficult.

在企业开发中,一个很常见的任务是发送电子邮件,而直接与Java Mail API打交道通常会很困难。

Spring Boot starter hides this complexity – mail dependencies can be specified in the following way:

Spring Boot启动器隐藏了这种复杂性–邮件依赖关系可以通过以下方式指定。

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

Now we can directly use the JavaMailSender, so let’s write some tests.

现在我们可以直接使用JavaMailSender,所以我们来写一些测试。

For the testing purpose, we need a simple SMTP server. In this example, we’ll use Wiser. This is how we can include it in our POM:

为了测试的目的,我们需要一个简单的SMTP服务器。在这个例子中,我们将使用Wiser。这样我们就可以把它包含在我们的POM中。

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

The latest version of Wiser can be found on Maven central repository.

Wiser的最新版本可以在Maven中央仓库上找到。

Here is the source code for the test:

这里是测试的源代码。

@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;
    }
}

In the test, the @Before and @After methods are in charge of starting and stopping the mail server.

在测试中,@Before@After方法负责启动和停止邮件服务器。

Notice that we’re wiring in the JavaMailSender bean – the bean was automatically created by Spring Boot.

注意,我们正在为JavaMailSenderbean布线–该bean是由Spring Boot自动创建的

Just like any other defaults in Boot, the email settings for the JavaMailSender can be customized in application.properties:

就像Boot中的其他默认值一样,JavaMailSender的电子邮件设置可以在application.properties中定制。

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

So we configured the mail server on localhost:25 and we didn’t require authentication.

因此,我们在localhost:25上配置了邮件服务器,而且我们不要求认证。

6. Conclusion

6.结论

In this article we have given an overview of Starters, explained why we need them and provided examples on how to use them in your projects.

在这篇文章中,我们概述了启动器,解释了为什么我们需要它们,并提供了如何在你的项目中使用它们的例子。

Let’s recap the benefits of using Spring Boot starters:

让我们回顾一下使用Spring Boot启动器的好处。

  • increase pom manageability
  • production-ready, tested & supported dependency configurations
  • decrease the overall configuration time for the project

The actual list of starters can be found here. Source code for the examples can be found here.

实际的启动器列表可以在这里找到。示例的源代码可以在这里找到。