读书笔记《developing-java-applications-with-spring-and-spring-boot-ebook》用于Spring Boot Apps的开发工具
我欠@springboot 很多。 #productivity #engineering #sota #minimalist #microservices #performance #quality #bestpractices
– Amir Sedighi @amirsedighi
在上一章中,您学习了如何使用 Spring Boot 的各种测试功能。我们看到了如何制作简单的单元测试、切片测试、模拟 WebFlux 测试,甚至是完全旋转的嵌入式 Netty 集成测试。
当我们步入正轨时,任何能够改变构建应用程序所花费时间曲线的东西都会受到赞赏。我们将探索 Spring Boot 带来的各种工具,以帮助我们破解我们的应用程序。
在本章中,我们将执行以下操作:
- Using Spring Boot's DevTools for hot code reloading and decaching
- Glean what Spring Boot did with its autoconfiguration report
- Make local changes and see them on the target system
- Write a custom health check
- Add build data to the
/application/info
endpoint - Create custom metrics
开发人员总是在寻找加速 事情了。很久以前,最大的加速之一是增量编译器,并且每次我们保存文件时都运行它们。现在它已渗透 现代工具,没有人会三思而后行。
在构建 Spring Boot 应用程序时,最需要的是检测代码更改并重新启动嵌入式容器的能力。
值得庆幸的是,我们只需要在上一章构建的代码中添加一个内容:
因此,这个微型模块执行以下活动:
- Disables cache settings for autoconfigured components
- When it detects a change in code, it restarts the application, holding onto third-party classes and simply throwing away and reloading custom classes
- Activates an embedded LiveReload (http://livereload.com/) server that can trigger the browser to refresh the page automatically
有关所有禁用组件的列表,请查看以下代码片段:
你问净收益是多少?
当我们对代码进行更改并发出 Save 或 Make Project ,DevTools 将丢弃保存我们自定义代码的类加载器并启动一个新的应用程序上下文。这使得重新启动相对较快。
Note
保存或制作项目? Spring Boot DevTools 监听文件更新。对于某些 IDE,例如 Eclipse,⌘-S 用于执行 Save 操作。 IntelliJ IDEA 会自动保存,因此另一个信号是 Make Project,⌘-F9,它会刷新环境。
在 LiveReload 服务器运行和 LiveReload 插件(http://livereload.com/extensions/) 安装在我们的浏览器中,我们可以在访问该站点时启用 LiveReloading。任何时候我们 更新代码,插件基本上都会为我们点击浏览器的刷新按钮。
Note
Restarting vs reloading:DevTools 提供了重新启动应用程序的能力很快,但它在各种方面受到限制。例如,不会选择通过添加新依赖项来更新类路径。不支持添加新类。对于处理这些复杂用例的更复杂的工具,您可能希望研究诸如 Spring Loaded (https://github.com/spring-projects/spring-loaded) 或 JRebel (http://zeroturnaround.com/software/jrebel/)。
清除所有这些缓存后,我们可以看到更改传播much 更快。让我们在调试模式下启动 LearningSpringBootApplication
来测试一下。如果我们访问该站点,事情看起来和预期的一样:
该站点从我们预加载的测试数据开始。要让浏览器监听更新,我们需要点击 LiveReload 图标:
起初,中心的点是空心的。启用后,圆点变为实心,如前面的屏幕截图所示。
让我们对模板进行一些编辑:
有了这个额外的子标题,我们只需要在 IDE 中点击 Save 或 Make Project。切换到浏览器将立即显示结果:
让我们对 HomeController
做一些调整,如下所示:
这与上一章相同,只是我们在模型中添加了一个新属性 extra
。我们可以通过调整模板来显示它:
这会将新的 extra
模型属性显示为 H4 标头,所有这些都无需在浏览器中单击任何内容:
使用 Spring Boot DevTools for 重新启动——任何内存中的数据或状态都将丢失。
这可能是好是坏。它当然鼓励您创建一个预加载器,可能带有 @Profile("dev")
注释,以便它仅在 spring 时运行。 profile.active=dev
已打开。
如果我们的用例需要很多步骤来设置,这可能会成为一个问题,并且重新启动应用程序会使我们一次又一次地重复这些步骤。内存数据库解决方案(例如 H2)放大了这一点。在我们的情况下,清除上传文件的启动代码会导致类似的数据刷新。
考虑不在浏览器中打开 LiveReload(但让应用程序重新启动)的另一个原因是,如果我们正在处理大量 JavaScript 的前端并且不希望每次更改都强制重新加载。例如,我们可能有一个填写了很多字段的页面。触发的重启可能会清除我们的表单并迫使我们重新输入数据。
正如我们目前在本书中看到的那样,Spring 引导自动配置 bean 以帮助我们避免配置基础设施,而是专注于编码业务需求。但是,有时,我们可能想知道 Spring Boot 为我们做了(或没有)做什么。
这就是为什么它有一个自动配置报告。本质上,每次基于 on 一些条件检查选择 bean 时,Spring Boot 都会记录决定(是或否)并提供它以许多不同的方式带给我们。
最简单的方法是将 --debug
添加到运行配置中。在下面的截图中,我们可以看到如何在 IntelliJ 中设置它:
如果我们使用 --debug
作为程序参数启动我们的应用程序,则会将自动配置报告打印到控制台:
这很好,在某些故障情况下,报告将自动打印出来以帮助进行事后分析。但是,从控制台获取报告并不是很有效。
如果我们使用 Spring Boot Actuator,我们可以在 in 更好的 JSON 结构。如果您还记得,我们在 Actuator ch10">第 10 章,Java 快速入门:
Note
如果您正在构建一个新应用程序并且没有在http://start.spring.io,这个依赖很有价值。
除了添加 Spring Boot的Actuator模块,我们还必须选择加入< /em> 或者启用它的功能。在 Spring Boot 2.0 中,Actuator 支持多种技术,包括 Spring MVC、Spring WebFlux 和 JMX。我们必须指出我们希望启用哪些平台,而不是期望 Spring Boot 猜测。为此,我们需要将以下代码行添加到我们的 application.properties
文件中:
从 HTTP 的角度来看,这将使 Actuator 的端点处于活动状态; (要为 JMX 启用执行器,我们需要将 endpoints.default.jmx.enabled
设置为 true
)。
当我们启动我们的应用程序时,会添加几个 Spring WebFlux 端点,提供额外的信息。要快速浏览 all 可用的端点,我们可以访问 http ://localhost:8080/application
,如下图所示:
此屏幕截图并未全部捕获,但有一长串端点提供有关我们应用程序的详细信息。 (顺便说一下,在本书的前面,我们只启用了一个执行器端点,/application/health
。这个标志让我们打开all 默认端点。)
从那里,我们可以在 http://localhost:8080/application/autoconfig
轻松找到自动配置报告,点击它,感谢 JSON查看器(https://github.com/tulios/json-viewer
),请参阅此 nicely 格式的报告:
好的,我们已经看到了几种生成此报告的方法。但它说是什么意思?
自动配置报告中的 JSON 片段可以描述如下:
ReactiveWebServerConfiguration.ReactorNettyAutoConfiguration
is a Spring Boot autoconfiguration policy that was evaluated, specifically on the subject of Netty.@ConditionalOnClass
matched on spotting Reactor'sHttpServer
class, glue code used by Reactor to embed the Netty container. This shows that Netty was on the classpath.@ConditionalOnMissingBean
is the second condition, and was negative, indicating there is no overriding, user-definedReactiveWebServerFactory
defined. Therefore, Spring Boot is activating its default policy for Reactor Netty.
要准确预测这个自动配置策略是什么,我们可以打开代码并自己检查。使用我们的 IDE,我们只需要查找父类 ReactiveWebServerConfiguration
:
这个来自 Spring Boot 的 Reactive web server configuration 代码的片段可以解释如下:
ReactiveWebServerConfiguration
is an abstract class that is merely used as a container for other policies@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
tells Spring Boot to back off and not use this if the user has declared such a bean elsewhere@ConditionalOnClass({HttpServer.class})
tells Spring Boot to only consider this if Reactor Netty is on the classpathstatic class ReactorNettyAutoConfiguration
names this rule used to autoconfigure Reactor Netty@Bean
flags the code as a Spring beanreturn new NettyReactiveWebServerFactory()
actually creates the Spring bean for Reactor Netty
所有这些结合在一起,允许在放入类路径时自动配置 Reactor Netty。我们在自动配置报告中发现了它。
Note
ReactiveWebServerConfiguration
中还有其他 bean 定义,包括对 Jetty、Apache Tomcat 和 Undertow 的支持,但由于篇幅限制未显示。
这有什么用?
如果我们尝试使用 Spring Boot 和 的某些功能,它不会按预期进行,要调试的一件事是是否正在创建预期的 bean。另一种用法是,如果我们正在为给定项目开发自己的自动配置模块,并且需要查看是否正在创建正确的 bean。
你看,自动配置报告并不局限于 Spring 团队发布的内容。它着眼于一切。
说到做出改变,请注意我们是如何让 Netty 在后台运行的。我们可以从控制台输出以及我们刚刚查看的自动配置报告中得知。
如果我们想更换容器怎么办?使用 Spring Boot 非常容易。我们只需要调整构建文件。
默认情况下,Spring Boot 将 Netty 用于 Reactive 应用程序,但切换起来并不难:
build.gradle
的变化如下:
- Excludes
spring-boot-starter-reactor-netty
from the reactive web dependency - Introduces
spring-boot-starter-undertow
as an alternative container
如果我们重新启动我们的应用程序并再次查看自动配置报告并 查找ReactorNettyAutoConfiguration< /code> 条目,我们会发现:
来自自动配置报告的新 JSON 片段显示我们刚才查看的相同策略现在已切换到 notMatched
。在细节上,它失败了,因为 @ConditionalOnClass
没有在类路径上发现 HttpServer
。
鉴于从 Reactor Netty 切换到 Undertow,在自动配置报告中搜索 Undertow
将导致我们这样做:
这个 JSON 片段显示 UndertowAutoConfiguration
现在生效,如下所示:
在进一步深入研究 UndertowReactiveWebServerFactory
时,我们将找到为基于 Reactor 的应用程序运行 Undertow 所需的所有细节。
到目前为止,我们已经了解了如何通过使用自动重启来加快开发人员的时间,并且我们已经收集了有关 Spring Boot 的信息,这要归功于它的自动配置报告。
开发人员的下一步通常是使用 IDE 的调试器。我们不会对此进行详细介绍 因为它高度特定于您使用的 IDE。但是,Spring Boot 提供的扩展价值是远程连接到 应用程序 并进行更改的机会。
想象一下,我们已经构建了我们的 应用程序 并将其推送到云端。我们在此环境中测试一个关键功能,因为这是将其与特定资源或特定配置相关联的唯一方法。好吧,进行更改的过程要昂贵得多。我们将不得不捆绑、重新部署、重新启动和重新导航。只需几行代码!
Spring Boot 的 DevTools 提供了将我们的 IDE 连接到远程运行的应用程序并通过网络推送代码更改的方法,从而使我们能够自动制作模块并立即对其进行测试。
为了做好准备,我们必须执行以下步骤:
- Add
spring.devtools.remote.secret=learning-spring-boot
toapplication.properties
. - Build the application using
./gradlew build
.
- Push the application to the cloud (Pivotal Web Services in this case with
cf push learning-spring-boot -p build/libs/learning-spring-boot-0.0.1-SNAPSHOT.jar
). - Instead of running the app locally in our IDE, run Spring Boot's
RemoteSpringApplication
class instead. - Add
https://learning-spring-boot.cfapps.io
(or whatever the app's remote URL is) as a program argument.
- Launch the
RemoteSpringApplication
configured runner.
以下屏幕截图显示了如何在 IntelliJ IDEA 中配置:
启动后,我们 IDE 中的控制台会显示 remote 横幅:
现在,我们可以自由地在我们的 IDE 中进行更改,保存/制作项目,并观察它们传播到我们在 https://learning-spring-boot 上运行的基于云的应用程序。 cfapps.io
。
首先,让我们在 src/main/resources/templates/index.html
处调整我们的模板。我们可以在主标题下方添加一个子标题,类似于我们在本章前面所做的:
点击 Save 或 Make Project,代码更改将上传到云端并触发重启(这是使用 LiveReload 服务器并自动刷新页面的好机会):
通过这个流程,我们可以进行 各种更改。准备就绪后,我们可以在本地commit 它们,构建一个更新的 JAR 文件,推送到云端,然后继续前进。
当我们将应用程序投入生产时,需要的另一个关键特性是监控它。在过去,人们会设置一个 CRON 作业来 ping 服务器并查看它是否已启动。更复杂的系统会跟踪磁盘使用情况、内存使用情况,并在数据库达到 95% 时对某人进行寻呼,因此可以在崩溃之前保存它。
Spring Boot 提供了health 检查监控的新纪元。首先,启动应用程序并访问 /application/health
:
开箱即用,这为我们提供了一个可以 ping 通的端点,此外,还为我们提供了一些有关磁盘空间的信息。它还包括一个自动包含的 MongoDB 健康检查。
但是如果我们需要编写自己的健康检查呢?也许,有一个我们依赖的系统。了解此上游服务是否不可用可能很有价值。
要编写我们自己的健康检查,我们只需要编写一个实现 Spring Boot 的 HealthIndicator
接口的 Spring 组件:
让我们剖析一下这个自定义健康指标:
@Component
marks this class so that Spring Boot picks it up and registers it automatically.- By implementing the
HealthIndicator
interface, Spring Boot will include it along with the pre-built health checks when we hit/application/health
. - The name
LearningSpringBootHealthIndicator
is used to create the indicator.HealthIndicator
will be trimmed off, and the remaining text will be formatted with lazy camel style. - There is but one method in this interface (meaning you could implement it using a Java 8 lambda),
health()
. It uses some plain old Java APIs to open a connection to a remote URL and fetch a status code. If the status code is good, it will build aHealth
status code ofUP
. Otherwise, it will build aHealth
status code ofDOWN
while also giving us the failed HTTP status code. - Finally, if any other exceptions occur, we will also get a
Health
status code ofDOWN
but with the information from the exception instead of a commonly coded error path.
让我们重新启动应用程序,看看我们的 /application/health
端点报告了什么:
我们可以看到我们的新健康指标 learningSpringBoot
,其状态为 UP
。
为了模拟失败,让我们通过将代码中的域切换到 greglturnquist.io
来更改 URL,然后看看会发生什么:
当我们重新启动并 ping /application/health
时,结果如下:
发生了几件事:
如果我们将 URL 更改为简单的 http://greglturnquist.com/foo
并重新启动,我们可以看到不同的状态:
在这种情况下,我们仍然有 DOWN
状态,但是报告了 HTTP 状态码 404
。 这些 指标对于观察我们应用程序的DevOps 团队来说非常有用。
了解问题核心的最大问题之一是知道正在运行的版本!您是否曾经接到客户报告系统损坏的凌晨 3:00 电话?在半醒的状态下,很容易开始尝试解决问题,但两个小时后才发现,客户正在running 一个较旧的版本,并且他们的问题已在上周修复。
解决方案是在每个版本中嵌入精确的版本,以便客户可以通过电话转发。然后,我们可以快速确定此问题是新问题、已修复问题还是回归问题。感兴趣的?
只需将其添加到 build.gradle
文件中,就在 buildscripts
部分的正下方:
这将向我们的系统添加一个新任务 generateGitProperties
。每当我们使用 Gradle 构建应用程序时,无论是打包一个可运行的 JAR 还是简单地启动它,都会生成一个新的 build/resources/main/git.properties
文件并通过 Spring Boot Actuator 的 /application/info
端点提供服务:
该报告为我们提供了时间戳、git commit hash 和分支。从长远来看,这一小块知识有可能为我们节省小时的工作量。
使用 Maven?有一个类似的插件:
它的工作原理相同。
一个额外的花絮——Spring Boot 有两种不同的 git 信息模式。显示的格式是 SIMPLE 模式。要获取更多详细信息,请将其添加到 application.properties
:
这将产生更详细的报告:
由每个团队决定哪个版本最有用,哪个版本不会泄露不必要的细节。
此外,我们可以通过将其添加到我们的 build.gradle 来获取有关 build 的更多详细信息
文件:
这个小小的添加,当我们运行 Gradle 的 build
任务时,会在我们的 JAR 文件中添加一个 build-info.properties
文件,显示像这样的内容:
这两个报告(一个简单的 git 报告 + 构建信息详细信息)都会为我们提供一些有用的信息,通过访问 localhost:8080/application/info
开始调试问题.
每个项目经理喜欢 指标。事实上,一家受欢迎的公司 (Netflix) 在这个领域非常有名,人们将其描述为一家碰巧流式传输视频的指标收集公司。
对于 Spring Boot,指标是 Spring Boot Actuator 功能的主要部分。如果我们访问/application/metrics
,我们可以看到一个列表指标:
这列出了所有种类的东西——内存、垃圾收集、堆与非堆、线程等等。这很好,但通常需要的是创建我们自己的指标的能力。
Spring Boot 提供了一个接口来注册我们自己的指标并让它们出现在同一页面上。立即提供的是获取 MeterRegistry
的能力。
为了使用这个三米注册表,我们需要将它注入到我们在 ImageService ">第 12 章,使用 Spring Boot 进行响应式数据访问:
此代码显示以下内容:
有了它,在 createImage
内部,我们可以定义自定义指标:
创建新图像的代码的第一部分是相同的,但接下来是 meterRegistry.summary("files.uploaded.bytes").record(...)
,这会创建一个名为 files.uploaded.bytes
的新 distribution summary。分发摘要包括名称、可选标签和值。注册的内容既是一个值,也是一个事件。每次添加一个计量器时,都会对其进行计数,并将 运行总数制成表格。
通过这些调整,我们可以刷新应用程序,等待它重新加载,然后上传几张图片,如下所示:
上传这些图片后,如果我们重新访问 /application/metrics
,我们可以看到我们新的 metric 在列表底部:
如果我们导航到http://localhost:8080/application/metrics/files.uploaded.bytes
,我们可以查看:
此 JSON 显示 三个 测量已注册到files.uploaded.bytes
,总计208020
字节。没有立即显示的还有这些指标的发布时间。可以使用新的 Micrometer 模块(http://micrometer.io)。
Note
Micrometer 是 Pivotal 的一个新项目。它是度量收集的门面。想想 SLF4J,但要考虑指标。它旨在与许多度量收集系统集成,包括 Atlas、Prometheus、Datadog、Influx、Graphite 等。在这种情况下,它使用的是基于内存的解决方案。由于它目前正在开发中并且可以保证它的自己的书,我们不会深入研究。
这只是可以定义的可能指标的一个示例。随意挖掘和试验数据。
Spring Boot Actuator 提供 很多 额外数据。以下 table 是一个快速总结:
执行器端点 |
说明 |
审计事件 |
|
自动配置 |
|
豆子 |
|
配置道具 |
|
环境 |
|
健康 |
|
堆转储 |
|
信息 |
|
日志文件 |
|
记录器 |
|
指标 |
|
映射 |
提供我们关于all< /a> Spring WebFlux 路由 |
地位 |
线程转储 |
创建线程转储报告 |
痕迹 |
Note
每一个都以 /application/
为前缀(默认情况下)。例如,health
位于 /application/health
。要覆盖此前缀,只需将 management.context-path
添加到 application.properties
并换出您喜欢的前缀(例如 /manager
)。此外,management.context-path
相对于 server.context-path
。
可以调整提供 Actuator 端点的端口。将 management.port
属性设置为 8081
会将所有这些端点的端口更改为 8081
。我们甚至可以通过设置
management.address=127.0.0.1
来调整使用的网络地址。此设置将使这些信息丰富的端点仅对本地框可见,并减少对外部连接的可见性。