SpringBoot 2 构建应用

开篇词

该指南提供了有关 Spring Boot 如何帮助你加速应用开发的示例。当你阅读更多 Spring 的入门指南时,你将看到更多 Spring Boot 用例。该指南旨在使你快速了解 Spring Boot。如果要创建自己的基于 Spring Boot 的项目,请访问 Spring Initializr,填写项目详细信息,选择选项,然后将捆绑的项目下载为 zip 文件。
 

你将创建的应用

我们将使用 Spring Boot 构建一个简单的 Web 应用,并向其中添加一些有用的服务。
 

你将需要的工具

如何完成这个指南

像大多数的 Spring 入门指南一样,你可以从头开始并完成每个步骤,也可以绕过你已经熟悉的基本设置步骤。如论哪种方式,你最终都有可以工作的代码。

  • 要从头开始,移步至从 Spring Initializr 开始
  • 要跳过基础,执行以下操作:
    • 下载并解压缩该指南将用到的源代码,或借助 Git 来对其进行克隆操作:git clone https://github.com/spring-guides/gs-spring-boot.git
    • 切换至 gs-spring-boot/initial 目录;
    • 跳转至该指南的创建简单的 Web 应用

待一切就绪后,可以检查一下 gs-spring-boot/complete 目录中的代码。
 

可以用 Spring Boot 来做什么

Spring Boot 提供了一种构建应用的快速方法。它查看我们的类路径和配置的 bean,对丢失的内容作出合理的假设,然后添加这些项目。借助 Spring Boot,我们可以将更多精力放在业务功能上,而不是在基础架构上。

以下示例展示了 Spring Boot 可以为你做什么:

  • Spring MVC 是否在类路径上?我们几乎总是需要几个特定的 bean,Spring Boot 会自动添加它们。Spring MVC 应用还需要一个 Servlet 容器,因此 Spring Boot 会自动配置嵌入式 Tomcat;
  • 类路径里是否有 Jetty?如果有的话,我们可能不想要 Tomcat,而想要嵌入式 Jetty。Spring Boot 会为你处理;
  • Thymeleaf 在类路径上吗?如果是的话,那必须始终将一些 bean 添加到我们的应用上下文。Spring Boot 为我们添加了它们。

这些只是 Spring Boot 提供的自动配置的一些示例。同时,Spring Boot 不会妨碍我们。例如,如果 Thymeleaf 在我们的路径上,则 Spring Boot 会自动将 SpringTemplateEngine 添加到我们的应用上下文中。但是,如果我们使用自己的设置定义自己的 SpringTemplateEngine,则 Spring Boot 不会进行添加操作。这样我们就可以减少做过多的改动。

Spring Boot 不会生成代码或对文件进行编辑。相反,当我们启动应用时,Spring Boot 会动态地连接 Bean 和设置并将其应用于我们的应用上下文。

从 Spring Initializr 开始

对于所有的 Spring 应用来说,你应该从 Spring Initializr 开始。Initializr 提供了一种快速的方法来提取应用程序所需的依赖,并为你完成许多设置。该示例仅需要 Spring Web 依赖。下图显示了此示例项目的 Initializr 设置:

上图显示了选择 Maven 作为构建工具的 Initializr。你也可以使用 Gradle。它还将 com.examplespring-boot 的值分别显示为 Group 和 Artifact。在本示例的其余部分,将用到这些值。

以下清单显示了选择 Maven 时创建的 pom.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>spring-boot</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-boot</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

以下清单显示了在选择 Gradle 时创建的 build.gradle 文件:

plugins {
	id 'org.springframework.boot' version '2.2.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

创建简单的 Web 应用

现在,我们可以为简单的 Web 应用创建 Web 控制器,以下清单(来自 src/main/java/com/example/springboot/HelloController.java)所示:

package com.example.springboot;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
public class HelloController {

	@RequestMapping("/")
	public String index() {
		return "Greetings from Spring Boot!";
	}

}

该类被标注为 @RestController,这意味着 Spring MVC 可以使用它来处理 Web 请求。@RequestMapping/ 映射到 index() 方法。从凌浏览器调用活在命令行上使用 curl 时,该方法返回纯文本。这是因为 @RestController 结合了 @Controller@ResponseBody 这两个注解,这两个注解使 Web 请求返回数据而不是视图。
 

创建应用类

Spring Initializr 为我们创建一个简单的应用类。但是,在这种情况下,它太简单了。我们需要修改应用类以匹配以下列表(来自 src/main/java/com/example/springboot/Application.java):

package com.example.springboot;

import java.util.Arrays;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

	@Bean
	public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
		return args -> {

			System.out.println("Let's inspect the beans provided by Spring Boot:");

			String[] beanNames = ctx.getBeanDefinitionNames();
			Arrays.sort(beanNames);
			for (String beanName : beanNames) {
				System.out.println(beanName);
			}

		};
	}

}

@SpringBootApplication 是一个便利的注解,它添加了以下所有内容:

  • @Configuration:将类标记为应用上下文 Bean 定义的源;
  • @EnableAutoConfiguration:告诉 Spring Boot 根据类路径配置、其他 bean 以及各种属性的配置来添加 bean。
  • @ComponentScan:告知 Spring 在 com/example 包中寻找他组件、配置以及服务。

main() 方法使用 Spring Boot 的 SpringApplication.run() 方法启动应用。

还有一个标注为 @BeanCommandLineRunner 方法,该方法在启动时运行。它检索由你的应用创建或由 Spring Boot 自动添加的所有 bean。它对它们进行排序并打印。
 

运行应用

要运行该应用,请在终端窗口(complete)目录中运行以下命令:

./gradlew bootRun

如果使用 Maven,请在终端窗口(complete)目录中运行以下命令:

./mvnw spring-boot:run

我们应该看到类似于以下内容的输出:

Let's inspect the beans provided by Spring Boot:
application
beanNameHandlerMapping
defaultServletHandlerMapping
dispatcherServlet
embeddedServletContainerCustomizerBeanPostProcessor
handlerExceptionResolver
helloController
httpRequestHandlerAdapter
messageSource
mvcContentNegotiationManager
mvcConversionService
mvcValidator
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration
org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$DispatcherServletConfiguration
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration
org.springframework.boot.context.embedded.properties.ServerProperties
org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
propertySourcesBinder
propertySourcesPlaceholderConfigurer
requestMappingHandlerAdapter
requestMappingHandlerMapping
resourceHandlerMapping
simpleControllerHandlerAdapter
tomcatEmbeddedServletContainerFactory
viewControllerHandlerMapping

我们可以清楚地看到 org.springframework.boot.autoconfigure.bean。还有一个 tomcatEmbeddedServletContainerFactory
现在,通过运行以下命令(及其输出显示),使用 curl(在单独的终端窗口中)运行该服务:

$ curl localhost:8080
Greetings from Spring Boot!

添加单元测试

我们将为创建的端点添加一个测试,Spring Test 为此提供了一些机制。
如果使用 Gradle,请将以下依赖添加到 build.gradle 文件中:

testImplementation('org.springframework.boot:spring-boot-starter-test') {
	exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}

如果使用 Maven,请将以下内容添加至 pom.xml 文件中:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
	<exclusions>
		<exclusion>
			<groupId>org.junit.vintage</groupId>
			<artifactId>junit-vintage-engine</artifactId>
		</exclusion>
	</exclusions>
</dependency>

现在编写一个简单的单元测试,以模拟通过我们的端点的 servlet 请求和响应,如以下清单(来自 src/test/java/com/example/springboot/HelloControllerTest.java)所示:

package com.example.springboot;

import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

	@Autowired
	private MockMvc mvc;

	@Test
	public void getHello() throws Exception {
		mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
				.andExpect(status().isOk())
				.andExpect(content().string(equalTo("Greetings from Spring Boot!")));
	}
}

MockMvc 来自 Spring Test,它使我们可以通过一组方便的构建器类将 HTTP 请求发送到 DispatcherServlet 中,并对结果进行断言。注意使用 @AutoConfigureMockMvc@SpringBootTest 来诸如 MockMvc 实例。使用 @SpringBootTest 之后,我们要求创建整个应用上下文。一种替代方法是要求 Spring Boot 通过使用 @WebMvcTest 仅创建上下文的 Web 层。无论哪种情况,Spring Boot 都会自动尝试找到应用的主应用类,但是如果我们要构建其他内容,则可以覆盖它或缩小它的范围。

除了模拟 HTTP 请求周期外,我们还可以使用 Spring Boot 编写简单的全栈集成测试。例如,除了(或连同)前面显示的模拟测试,我们可以创建以下测试(来自 src/test/java/com/example/springboot/HelloControllerIT.java):

package com.example.springboot;

import static org.assertj.core.api.Assertions.*;

import java.net.URL;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.ResponseEntity;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloControllerIT {

	@LocalServerPort
	private int port;

	private URL base;

	@Autowired
	private TestRestTemplate template;

    @BeforeEach
    public void setUp() throws Exception {
        this.base = new URL("http://localhost:" + port + "/");
    }

    @Test
    public void getHello() throws Exception {
        ResponseEntity<String> response = template.getForEntity(base.toString(),
                String.class);
        assertThat(response.getBody().equals("Greetings from Spring Boot!"));
    }
}

由于 webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT 设置,嵌入式服务器从一个随机端口启动,并且在运行时使用 @LocalServerPort 来发现实际端口。
 

添加生产级别服务

如果要为我们的企业构建网站,则需要添加一些管理服务。Spring Boot 的执行器模块提供了多种该类服务(例如运行状况、审计、bean 等等)。

如果使用 Gradle,请将以下依赖添加到 build.gradle 文件中:

implementation 'org.springframework.boot:spring-boot-starter-actuator'

如果使用 Maven,请将以下依赖添加到 pom.xml 文件中:

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

然后重新启动应用。如果使用 Gradle,请在终端窗口(complete 目录)中运行以下命令:

./gradlew bootRun

如果使用 Maven,请在终端窗口(complete 目录)中运行以下命令:

./mvnw spring-boot:run

我们应该看到已经向应用添加了一组新的 RESTful 端点。这些是 Spring Boot 提供的管理服务。以下清单显示了典型的输出:

management.endpoint.configprops-org.springframework.boot.actuate.autoconfigure.context.properties.ConfigurationPropertiesReportEndpointProperties
management.endpoint.env-org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointProperties
management.endpoint.health-org.springframework.boot.actuate.autoconfigure.health.HealthEndpointProperties
management.endpoint.logfile-org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointProperties
management.endpoints.jmx-org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointProperties
management.endpoints.web-org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties
management.endpoints.web.cors-org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties
management.health.status-org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorProperties
management.info-org.springframework.boot.actuate.autoconfigure.info.InfoContributorProperties
management.metrics-org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties
management.metrics.export.simple-org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleProperties
management.server-org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties
management.trace.http-org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceProperties

actuator 暴露了以下特性:

还有一个 /actuator/shutdown 端点,但是默认情况下,它仅通过 JMX 可见。要将其启用为 HTTP 端点,请在 application.properties 文件中添加 management.endpoints.web.exposure.include=health,info,shutdown。但是,我们可能不应该为公共可用的应用启用关闭端点。

我们可以通过运行以下命令来检查应用的运行状况:

$ curl localhost:8080/actuator/health
{"status":"UP"}

我们还可以尝试通过 curl 调用 shutdown,以查看未将必要的行(如前一备注所示)添加至 application.properties 时会发生什么情况:

$ curl -X POST localhost:8080/actuator/shutdown
{"timestamp":1401820343710,"error":"Method Not Allowed","status":405,"message":"Request method 'POST' not supported"}

由于我们没有启用它,所以请求被阻塞(因为端点不存在)。

有关这些 REST 端点中的每个端点以及如何使用 application.properties 文件(在 src/main/resources 中)调整其设置的更多详细信息,请参阅有关端点的文档
 

查看 Spring Boot 启动器

我们已经看到了 Spring Boot 的一些 “启动器”,我们可以在源代码中看到它们。
 

JAR 支持于 Groovy 支持

最后一个示例显示了 Spring Boot 如何让我们连接一些我们所不知道的 bean。它还显示了如何打开便捷的管理服务。

但是,Spring Boot 的作用还不止这些。借助 Spring Boot 的加载模块,它不仅支持传统的 WAR 文件部署,还使我们可以组合可执行的 JAR。各种指南通过 spring-boot-gradle-pluginspring-boot-maven-plugin 展示了这种双重支持。

最重要的是,Spring Boot 还具有 Groovy 支持,使我们仅用一个文件就可以构建 Spring MVC Web 应用。

创建一个名为 app.groovy 的新文件,并将以下代码放入其中(来自 src/test/java/com/example/springboot/app.groovy):

@RestController
class ThisWillActuallyRun {

    @RequestMapping("/")
    String home() {
        return "Hello, World!"
    }

}

文件在哪里都没有关系。我们甚至可以在一个推文中包含一个很小的应用!

接下来,安装 Spring Boot 的 CLI

通过运行以下命令来运行 Groovy 应用:

$ spring run src/main/java/com/example/springboot/app.groovy

关闭前一个应用,以避免端口冲突。

在另一个终端窗口中,运行以下 curl 命令(及其输出显示):

$ curl localhost:8080
Hello, World!

Spring Boot 通过在代码中动态添加关键注解并使用 Groovy Grape 来拉低使用应用运行所需的库来实现该目的。
 

参见

以下指南也可能会有所帮助:

想看指南的其他内容?请访问该指南的所属专栏:《Spring 官方指南

发布了154 篇原创文章 · 获赞 10 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/stevenchen1989/article/details/104323553