SpringCloud与微服务-第2章-SpringBoot基础回顾

第 2 章 – SpringBoot 快速入门

在展开 Spring Cloud 的微服务架构部署之前,我们先通过本章的内容来了解一下用于构建微服务的基础框架——Spring Boot


在本章中我们将介绍下面这些与后续课程有密切联系的内容。

目标:

  • 如何构建 Spring Boot 项目
  • 如何实现 RESTful API 接口
  • 如何实现多环境的 Spring Boot 应用配置
  • Spring Boot 应用的监控与管理

Spring Boot 框架简介

Spring Boot 可以轻松创建独立的、生产级的基于 Spring 的应用程序,可以“直接运行”。Spring 平台可以轻松集成常用的第三方库。大多数 Spring Boot 应用程序只需要最少的 Spring 配置。

特征

  • 创建独立的 Spring 应用程序
  • 直接嵌入 Tomcat、Jetty 或 Undertow(无需部署 WAR 文件)
  • 提供“starter”依赖项以简化您的构建配置
  • 尽可能自动配置 Spring 和 第三方方库
  • 提供为生产环境准备的功能,例如指标、健康检查和外部配置
  • 绝对没有代码生成,也不需要 XML 配置

项目构建与解析

系统及工具版本要求

  • Java 8 及以上版本(这里选择 jdk11)
  • IntelliJ IDEA 2020 及以上版本

使用 IDEA 快速创建应用

1.打开新建项目选项卡

选中 Spring Initializr 功能,选择项目 SDK(此处以 JDK 11 为例),最后点击下一步。

bg right fit


2.填写版本信息和项目信息

image-20240413220440276


3.选择相关初始化依赖

image-20240413220511660


4.选择项目的本地路径

image-20240413220535228


工程结构解析

  • src/main/java:源代码目录,该目录用来存放应用的源代码,其中 com.example.demo 包名是由我们在创建项目时指定的。
  • src/main/resources:资源文件目录,该目录用来存放应用的配置文件,如 application.properties、application.yml 等。
  • src/test:测试代码目录,该目录用来存放应用的测试代码。

Maven 配置分析

打开当前工程下的 pom.xml 文件,看看生成的项目都引入了哪些依赖来构建 Spring Boot 工程,内容大致如下所示。


在基础信息部分,groupld 和 artifactld 对应生成项目时页面上输入的内容。另外 Spring Boot 默认将该微服务应用打包为 jar 的形式,而非 war 的形式,因为默认的 Web 模块依赖会包含嵌入式的 Tomcat,这样使得我们的应用 jar 自身就具备了提供 Web 服务的能力,后续我们会演示如何启动它。


父项目 parent 配置指定为 spring-boot-starter-parent 的 2.7.1 版本,该父项目中定义了 Spring Boot 版本的基础依赖以及一些默认配置内容,比如,配置文件 application.properties 的位置等。在项目依赖 dependencies 配置中,包含了下面两项。

  • spring-boot-starter-web:全桟 Web 开发模块,包含嵌入式 Tomcat、Spring MVC。
  • spring-boot-starter-test:通用测试模块,包含 JUnit、Hamcrest、Mockito。

这里所引用的 web 和 test 模块,在 Spring Boot 生态中被称为 Starter POMs。Starter POMs 是一系列轻便的依赖包,是一套一站式的 Spring
相关技术的解决方案。开发者在使用和整合模块时,不必再去搜寻样例代码中的依赖配置来复制使用,只需要引入对应的模块包即可。


Spring Boot 的 官方 Starter POMs 采用 spring-boot-starter-xxx的命名方式,*代表一个特别的应用功能模块,比如这里的 web、test。

另外 xxx.sring-boot-starter 命名的模块是非官方的第三方模块,比如 mybatis-spring-boot-starter


文档:
https://docs.spring.io/spring-boot/docs/2.3.12.RELEASE/reference/html/index.html


实现 RESTful API

在 Spring Boot 中创建一个 RESTful API 的实现代码同 Spring MVC 应用一样,只是不需要像 Spring MVC 那样先做很多配置,而是像下面这样直接开始编写 Controller 内容:

  • 新建 package,可根据实际的构建情况修改成自己的路径。
  • 新建 HelloWorldController 类,内容如下所示。


  • 找到启动类,启动该应用

image-20220711233735883


  • 启动成功,默认端口 8080

    image-20220711233826742


image-20220711233007071


  • 在服务器上部署运行时,通常先使用 mvn package 或 mvn install(双击即可) 将应用打包成 jar 包,再通过 java -jar xxx.jar 来启动应用。

image-20220711233958684


编写单元测试

功能实现之后,我们要养成随手写配套单元测试的习惯,这在微服务架构中尤为重要。

单元测试是在开发过程中用来验证代码正确性非常好的手段,并且这些单元测试将会很好地支持我们未来可能会进行的重构。


在 Spring Boot 中实现单元测试同样非常方便,下面我们编写一个简单的单元测试来模拟 HTTP 请求,测试之前实现的/hello 接口,该接口应返回 Hello World 字符串。

该单元测试使用 RestTemplate 类模拟 发出 HTTP 请求.


1. 声明 RestTemplate 类


2.编写单元测试类


3.点击测试方法左侧按钮,开始测试

image-20220711235420676


4.测试结果

image-20220711235510407


5.注意事项

使用 RestTemplate 进行访问时,需要确保服务端保持活动状态,否则会测试不通过.

image-20220711235804341


快速入门小结

我们通过 IDEA 工具构建了一个 Spring Boot 的基础项目,并详细介绍了该基础项目的结构及 Maven 的依赖关系,接着在该项目中实现一个输出“Hello World”的 RESTful 接口以及针对该接口的单元测试用例,完成了一个虽然简单,但涵盖了项目构建、服务开发、单元测试的全套开发内容。


我们在后续使用 Spring Cloud 的时候会构建多个 Spring Boot 的项目来实现微服务架构中的基础设施以及微服务应用,通过本节的学习,我们己经具备了使用 Spring Boot 来构建简单微服务项目的基本能力。我们将对后续在 Spring Cloud 组件使用过程中会涉及的配置内容做一些介绍和解释。


配置详解

我们已经轻松地实现了一个简单的 RESTful API 应用,体验了 Spring Boot 的诸多优点。在配置方面,除了 Maven 的配置之外,没有引入任何其他配置。这就是之前我们提到的,Spring Boot 针对常用的开发场景提供了一系列自动化配置来减少原本复杂而又几乎很少改动的模板化配置内容。


但是,我们还是需要了解如何在 Spring Boot 中修改这些自动化的配置内容,以应对一些特殊的场景需求。比如,我们在同一台主机上需要启动多个基于 Spring Boot 的 Web 应用,若不为每个应用指定特别的端口号,那么默认的 8080 端口必将导致冲突。


配置文件

我们在使用 Spring Cloud 的各个组件的时候,其实有大量的工作都会是针对配置文件的。所以我们有必要深入了解一些关于 Spring Boot 中的配置文件的知识,比如配置方式、如何实现多环境配置、配置信息的加载顺序等


Spring Boot 的工程结构 src/main/ resources 目录是 Spring Boot 的配置目录,所以当要为应用创建个性化配置时,应在该目录下进行。Spring Boot 的默认配置文件位置为 src/main/resources/application.properties

image-20220712110030957

上图在配置文件中定义了应用的端口号以及上下文路径.


关于 Spring Boot 应用的配置内容都可以集中在该文件中,根据我们引入的不同 Starter 模块,可以在这里定义容器端口号、数据库连接信息、日志级别等各种配置信息。Spring Boot 的配置文件除了可以使用传统的 properties 文件之外,还支持现在被广泛推荐使用的
YAML 文件。

image-20220712110332417


通过 YAML 的配置方式我们可以看到,配置信息利用阶梯化缩进的方式,其结构更为清晰易读,同时配置内容的字符量也得到显著减少。后续的配置文件,我们将逐步使用 YAML 方式进行编写.


YAML(英语发音为/;jaem3l/,尾音类似 camel 骆驼)是一个可读性高,用来表达资料序列的格式。YAML 的意思其实是:Yet Another Markup Language (仍是一种标记语言),但为了强调这种语言以数据作为中心,而不是以标记语言为重点,而用反向缩略语重新命名。

YAML 的语法特别适合用来表达或编辑数据结构、各种设定文档、文件大纲(例如,许多电子邮件标题格式和 YAML 非常接近)。尽管它比较适合表达阶层式(hierarchical model)的数据结构,不过也有精致的语法可以表示关联性(relational model)的数据结构。

由于 YAML 使用空白符号和分行来分隔资料,其让人最容易上手的特色是巧妙避开各种封闭符号,如引号、各种括号等,这些符号在 xml 结构时会变得复杂而难以辨认。


自定义参数

除了可以在 Spring Boot 的配置文件中设置各个 Starter 模块中预定义的配置属性,也可以在配置文件中定义一些我们需要的自定义属性。比如在 application.yml 中添加:


自定义 Book 类,使用@Value 进行属性注入


@Value 注解加载属性值时可以支持两种表达式来进行配置,如下所示。

  • 一种是上面介绍的 PlaceHolder 方式,格式为${ • • • },大括号内为 PlaceHolder。
  • 另一种是使用 SpEL 表达式(Spring Expression Language),格式为#{•••},大括号内为 SpEL 表达式

编写单元测试


启动测试,测试结果将在控制台输出:

image-20220712112643626


参数引用

在 application .yml 中的各个参数之间可以直接通过使用 PlaceHolder 的方式来进行引用,就像下面的设置 :


修改 Book 类,添加 desc 属性.


单元测试步骤同上.测试成功将在控制台打印:

image-20220712114324986


多环境配置

我们在开发应用的时候,通常同一套程序会被应用和安装到几个不同的环境中,比如开发、测试、生产等。其中每个环境的数据库地址、服务器端口等配置都不同,如果在为不同环境打包时都要频繁修改配置文件的话,那必将是个非常烦琐且容易发生错误的事。

Spring Boot 通过配置多份不同环境的配置文件,实现多环境配置更加简单.


在 Spring Boot 中,多环境配置的文件名需要满足 application-{profile}.yml 的格式(我们以.yml 格式为例),其中{profile}对应你的环境标识,如下所示:

  • application-dev.yml:开发环境。
  • application-test.yml:测试环境。
  • application-prod.yml:生产环境。

至于具体哪个配置文件会被加载,需要在 application.yml 文件中通过 spring.profiles.active 属性来设置,其值对应配置文件中的{profile}值。如 spring.profile.active=dev 就会加载 application-dev.yml 配置文件内容。


如下所示:

image-20220712122558581


多环境的配置思路:

  • application.yml 中配置通用内容,并设置 spring.profiles.active=dev,以开发环境为默认配置。
  • application-{profile}.yml 中配置各个环境不同的内容。

加载顺序

在上面的例子中,我们将 SpringBoot 应用需要的配置内容都放在了项目工程中,己经能够通过 spring.profiles.active 来实现多环境的支持。但是,当团队逐渐壮大,分工越来越细致之后,往往不需要让开发人员知道测试或是生产环境的细节,而是希望由每个环境各自的负责人(QA 或是运维)来集中维护这些信息。


那么如果还是以这样的方式存储配置内容,对于不同环境配置的修改就不得不去获取工程内容来修改这些配置内容,当应用非常多的时候就变得非常不方便。同时,配置内容对开发人员都可见,这本身也是一种安全隐患。对此,出现了很多将配置内容外部化的框架和工具,后续将要介绍的 Spring Cloud Config 和Spring Cloud Alibaba Nacos就是一些解决方案,为了后续能更好地理解 这些解决方案 的加载机制,我们需要对 Spring Boot 对数据文件的加载机制有一定的了解。


为了能够更合理地重写各属性的值,Spring Boot 使用了下面这种较为特别的属性加载顺序:

  1. 在命令行中传入的参数。
  2. SPRING_APPLICATION_JSON 中的属性。SPRING_APPLICATION_JSON 是以 JSON 格式配置在系统环境变量中的内容。
  3. java:comp/env 中的 JNDI 属性。
  4. Java 的系统属性,可以通过 System.getProperties()获得的内容。
  5. 操作系统的环境变量。
  6. 通过 random.* 配置的随机属性。

优先级按上面的顺序由高到低,数字越小优先级越高。


  1. 位于当前应用 jar 包之,针对不同{profile}环境的配置文件内容,例如 application-{profile}.properties 或是 YAML 定义的配置文件。
  2. 位于当前应用 jar 包之,针对不同{profile}环境的配置文件内容,例如 application-{profile}.properties 或是 YAML 定义的配置文件。
  3. 位于当前应用 jar 包之外的 application.properties 和 YAML 配置内容。

可以看到,其中第 7 项和第 9 项都是从应用 jar 包之外读取配置文件,所以,实现外部化配置的原理就是从此切入,为其指定外部配置文件的加载位置来取代 jar 包之内的配置内容。通过这样的实现,我们的工程在配置中就变得非常干净,只需在本地放置幵发需要的配置即可,而不用关心其他环境的配置,由其对应环境的负责人去维护即可。


  1. 位于当前应用 jar 包之内的 application.properties 和 YAML 配置内容。
  2. @Configuration 注解修改的类中,通过 @PropertySource 注解定义的属性。
  3. 应用默认属性,使用 SpringApplication.setDefaultProperties 定义的内容。

配置加载优先级通用原理总结:

  • 距离用户越近,优先级越高,距离程序越近,优先级越低。
  • 个性化配置优先级高于通用化配置

活动 2.1

创建 SpringBoot 应用,使用 RestTemplate 进行互相调用。


监控与管理

在微服务架构中各个应用的内部逻辑因分解而得以简化,但是由于部署应用的数量成倍增长,使得系统的维护复杂度大大提升。对于运维人员来说,为了能对这些成倍增长的应用做到高效运维,传统的运维方式显然是不合适的,所以我们需要实现一套自动化的监控运维机制,而这套机制的运行基础就是不间断地收集各个微服务应用的各项指标情况,并根据这些基础指标信息来制定监控和预警规则,更进一步甚至做到一些自动化的运维操作等。


当我们决定用 Spring Boot 来作为微服务框架时,除了它强大的快速开发功能之外,还因为它在 Starter POMs 中提供了一个特殊依赖模块 spring-boot-starter-actuator

引入该模块能够自动为 SpringBoot 构建的应用提供一系列用于监控的端点。当然,它也并不是万能的,有时候也需要对其做一些简单的扩展来帮助我们实现自身系统个性化的监控需求。所以,在本节将详细介绍一些关于 spring-boot-starter-actuator 模块的内容,包括原生提供的端点以及一些常用的扩展和配置方式等。


初识 actuator

下面,我们通过对“快速入门”小节中实现的 Spring Boot 应用增加 spring-boot- starter-actuator 模块功能,来对它有一个直观的认识。在现有的 Spring Boot 应用中引入该模块非常简单,只需要在 pom. xml 的 dependency 节点中,新增 spring-boot-starter-actuator 的依赖即可,具体如下:


增加该依赖之后,重新启动应用。此时输出:

image-20220712193352403

上图显示了端点定义,这个端点并非我们自己在程序中创建的,而是由 spring-boot-starter-actuator 模块根据应用依赖和配置自动创建出来的监控和管理端点。通过这个端点,我们可以实时获取应用的各项监控指标


比如访问/actuator 端点。我们可以获得如下类似信息:


在没有引入其他依赖之前,该端点的内容较为简单,后续我们在使用 Spring Cloud 的各个组件之后,它的返回会变得非常丰富,这些内容将帮助我们制定更为个性化的监控策略。


原生端点

通过在快速入门示例中添加 spring-boot-starter-actuator 模块,我们已经对它有了一个初步的认识。接下来,我们详细介绍一下 spring-boot-starter-actuator 模块中己经实现的一些原生端点。根据端点的作用,可以将原生端点分为以下三大类。

  • 应用配置类:获取应用程序中加载的应用配置、环境变量、自动化配置报告等与 SpringBoot 应用密切相关的配置类信息。
  • 度量指标类:获取应用程序运行过程中用于监控的度量指标,比如内存信息、线程池信息、HTTP 请求统计等。
  • 操作控制类:提供了对应用的关闭等操作类功能。

出于安全考虑,某些端点默认是没有对外暴露的.为方便测试,我们进行手动开启.

在 application.yml 中添加如下配置:


下面我们来详细了解一下这三类端点都分别可以为我们提供怎样的有用信息和强大功能,以及我们如何去扩展和配置它们。


应用配置类

由于 Spring Boot 为了改善传统 Spring 应用繁杂的配置内容,采用了包扫描和自动化配置的机制来加载原本集中于 XML 文件中的各项内容。虽然这样的做法让我们的代码变得非常简洁,但是整个应用的实例创建和依赖关系等信息都被离散到了各个配置类的注解上,这使我们分析整个应用中资源和实例的各种关系变得非常困难。而这类端点可以帮助我们轻松获取一系列关于 Spring 应用配置内容的详细报告,比如 Bean 创建的报告、环境属性的报告等。


/beans

该端点用来获取应用上下文中创建的所有 Bean。以本项目 dev 环境为例,启动后访问: http://localhost:8081/dev/actuator/beans ,可获取如下信息(部分展示):

image-20220712210434708


在如上示例中,我们可以看到在每个 Bean 中都包含了下面这些信息 。

  • scope:Bean 的作用域。
  • type:Bean 的 Java 类型。
  • resource:class 文件的具体路径。
  • dependencies:依赖的 Bean 名称 。

/configprops:

以本项目 dev 环境为例,启动后访问: http://localhost:8081/dev/actuator/configprops 。该端点用来获取应用中配置的属性信息报告。如下所示,prefix 属性代表了属性的配置前缀,properties 代表了各个属性的名称和值。

image-20220712212525622


所以,我们可以通过该报告来看到各个属性的配置路径,比如我们要关闭该端点,就可以通过使用 endpoints.configprops.enabled=false 来完成设置。如下所示,添加该配置后重启应用即可关闭 /configprops 端点


/env:

以本项目 dev 环境为例,启动后访问: http://localhost:8081/dev/actuator/env。该端点与/configprops 不同,它用来获取应用所有可用的环境属性报告,其中还包括了应用还没有使用的配置,所以它可以帮助我们方便地看到当前应用可以加载的配置信息,并配合@ConfigurationProperties 注解将它们引入到我们的应用程序中来进行使用。另外,为了配置属性的安全,对于一些类似密码等敏感信息,该端点都会进行隐私保护,但是我们需要让属性名中包含 password、secret、key 这些关键词,这样该端点在返回它们的时候会使用 * 来替代实际的属性值。


image-20220712213122940


/mappings:

以本项目 dev 环境为例,启动后访问: http://localhost:8081/dev/actuator/mappings。该端点用来返回所有 Spring MVC 的控制器映射关系报告。

image-20220712213559520


度量指标类

上面我们所介绍的应用配置类端点可以说是一个静态报告。而度量指标类端点提供的报告内容则是动态变化的,这些端点提供了应用程序在运行过程中的一些快照信息,比如内存使用情况、HTTP 请求统计、外部资源指标等。

这些端点对于我们构建微服务架构中的监控系统非常有帮助,由于 Spring Boot 应用自身实现了这些端点,所以我们可以很方便地利用它们来收集我们想要的信息,以制定出各种自动化策略。下面,我们就来分别看看这些强大的端点功能。


/metrics:

以本项目 dev 环境为例,启动后访问: http://localhost:8081/dev/actuator/metrics

该端点用来返回当前应用的各类重要度量指标,比如内存信息、线程信息、垃圾回收信息等。


如下所示(部分):

image-20220713112701319


在当前路径后拼接上面路径即可查看对应详细信息. 如拼接"disk.free" ,访问: http://localhost:8081/dev/actuator/metrics/disk.free

可以获知当前磁盘剩余可用容量。

image-20220713113557094


/health:

以本项目 dev 环境为例,启动后访问: http://localhost:8081/dev/actuator/health。该端点用来获取应用的各类健康指标信息。如下所示:

image-20220713115753613


当前项目较为简单,只标识出应用的状态.后续集成 Spring Cloud 组件后,返回信息将变得丰富起来.状态码解释如下:

  • UNKNOWN:未知状态,映射 HTTP 状态码为 503
  • UP:正常,映射 HTTP 状态码为 200
  • DOWN:失败,映射 HTTP 状态码为 503
  • OUT_OF_SERVICE:不能对外提供服务,但是服务正常。映射 HTTP 状态码为 200

操作控制类

操作控制类端点拥有更强大的控制能力,如果要使用它们的话,需要通过属性来配置开启操作。

在原生端点中,只提供了一个用来关闭应用的端点:/shutdown(在后续我们引入了 Eureka 之后,会引入更多控制端点)。可以通过如下配置开启它:

image-20220713122012395


在配置了上述属性之后,只需要访问该应用的/shutdown 端点就能实现关闭该应用的远程操作。由于开放关闭应用的操作本身是一件非常危险的事,所以真正在线上使用的时候,需要对其加入一定的保护机制,比如定制 actuator 的端点路径、整合 Spring Security 进行安全校验等。

该端点不支持 Get 请求,我们可以借助 PostMan 等类似工具发送 POST 请求.

image-20220713121939085


活动 2.2


在 Spring Boot 项目中通过 actuator 端点查看应用的相关信息.

小问题 :

以下哪个内部类在定义时可以没有类名称?

  • A. 正则内部类
  • B. 静态内部类
  • C. 方法 – 局部内部类
  • D. 匿名内部类
答案

D


启用热部署以提升开发效率

IDEA 2021.2 版本 DevTools 热部署为例

首先引入依赖


修改 Settings 里 Compiler 选项下的配置,将下图中红色方框里的选项全部勾上

bg


修改 Advanced Settings 里的配置,将下图的选项勾上


注意 Advanced Settings 选项只有在 File->Settings 里面才有,而在 File->New Projects Setup->Settings for New Projects 这个设置页面里是没有的,所以只能设置本项目,而不能自动设置新建的项目。

如果使用的是 IDEA 2021.2 之前版本的话还是使用快捷键 shift+Ctrl+Alt+/,选择 Registry…,将 compiler.automake.allow.when.app.running 选项勾上。

完成上面的步骤后重启下 IDEA 基本就没问题了,如果还是不行的话建议检查 pom 和 application 文件是否引入了 DevTools 依赖并且正确配置。


练习问题


  1. 下面哪个选项不是 Spring Boot 的基础结构?
  • a. src/main/java
  • b. src/main/resources
  • c. src/test:
  • d. src/main/spring
答案

d


  1. 我们在使用 Restful 风格进行编程的时候,是遵循了配置大于约定的规范。
  • a. 错误
  • b. 正确
答案

a


  1. 下面哪个不是 Spring Boot 应用的配置文件?
  • a. application.yml
  • b. application.yaml
  • c. userservice.xml
  • d.application.properties
答案

c


  1. 在 Spring Boot 应用中,不必引入 spring-boot-starter-actuator 的 Maven 即可实现端点监控?

    a. 正确
    b. 错误

    答案

    b


小结

  • 本章我们通过构建一个最基本的 Spring Boot 工程,让大家对其有了一个最直观的感受。
  • 为后续构建各类 Spring Cloud 组件和微服务应用做了一些基础准备工作。
  • 另外,我们对 SpringBoot 中的配置原理以及监控管理做了深入的介绍,因为这些内容将在后续的介绍中有所涉及,并且它们有助于理解 Spring Cloud 组件的运行原理。
  • 更多关于使用 Spring Boot 开发微服务应用的内容,我们不在本书中详细介绍,读者可参阅官方文档或其他书籍资料来学习

Views: 8