15.2.2 查看配置详细信息
除了获取有关应用程序的一般信息之外,了解应用程序的配置信息也很有用。应用程序上下文中有哪些 bean?哪些自动配置条件通过或失败?应用程序可以使用哪些环境属性?HTTP 请求如何映射到控制器?一个或多个包或类设置为怎样的日志级别?
这些问题由 Actuator 的 /beans
、/conditions
、/env
、/configprops
、/mappings
和 /loggers
端点回答。 在某些情况下,例如 /env
和 /loggers
,您甚至可以动态调整正在运行的应用程序的配置。从 /beans
端点开始,我们将查看每一个端点,以深入了解正在运行的应用程序的配置。
获取 Bean Wiring 报告
探索 Spring 应用程序上下文最重要的端点是 /beans
端点。此端点返回一个 JSON 文档,描述应用程序上下文中的每个 bean、它的 Java 类型以及它注入的任何其他 bean。
对 /beans
的 GET 请求所得到的完整响应信息非常多,可以轻松地填满本章。作为完整响应的替代,让我们考虑以下片段,它专注于单个 bean 条目:
{
"contexts": {
"application-1": {
"beans": {
...
"ingredientsController": {
"aliases": [],
"scope": "singleton",
"type": "tacos.ingredients.IngredientsController",
"resource": "file [/Users/habuma/Documents/Workspaces/
TacoCloud/ingredient-service/target/classes/tacos/ingredients/
IngredientsController.class]",
"dependencies": [
"ingredientRepository"
]
},
...
},
"parentId": null
}
}
}
响应的根是 contexts 元素,它包含应用程序中每个 Spring 应用程序上下文的一个子元素。在每个应用程序上下文中都有一个 beans 元素,其中包含应用程序上下文中所有 bean 的详细信息。
在前面的示例中,显示的 bean 是名称为 ingredientsController
的 bean。您可以看到它没有别名,范围为单例,并且类型为 tacos.ingredients.IngredientsController
。此外,资源属性给出了定义 bean 的类文件的路径。并且 dependencies 属性列出了注入给定 bean 的所有其他 bean。 在这种情况下,ingredientsController
bean 被注入了一个名称为 ingredientRepository
的 bean。
解释自动配置
如您所见,自动配置是 Spring Boot 提供的最强大的功能之一。但是,有时您可能想知道为什么会自动配置某些内容。或者您可能期望某些东西被自动配置,想知道它为什么没有被自动配置。在这种情况下,您可以向 /conditions
发出 GET 请求,以了解自动配置的情况。
/conditions
返回的自动配置报告分为三部分:positiveMatches(条件配置通过)、negativeMatches(条件配置失败)和 unconditionalClasses(无条件类)。以下是 /conditions
请求的响应的片段,示例显示了每个部分:
{
"contexts": {
"application-1": {
"positiveMatches": {
...
"MongoDataAutoConfiguration#mongoTemplate": [
{
"condition": "OnBeanCondition",
"message": "@ConditionalOnMissingBean (types
:org.springframework.data.mongodb.core.MongoTemplate;
SearchStrategy: all) did not find any beans"
}
],
...
},
"negativeMatches": {
...
"DispatcherServletAutoConfiguration": {
"notMatched": [
{
"condition": "OnClassCondition",
"message": "@ConditionalOnClass did not find required
class 'org.springframework.web.servlet.
DispatcherServlet'"
}
],
"matched": []
},
...
},
"unconditionalClasses": [
...
"org.springframework.boot.autoconfigure.context.
ConfigurationPropertiesAutoConfiguration",
...
]
}
}
}
在 positiveMatches 部分,您会看到 MongoTemplate bean 是由自动配置配置的,且因为它不存在。导致这种情况的自动配置是因为有 @ConditionalOnMissingBean
注释,如果尚未显式配置要配置的 bean,则它会传递要配置的 bean。在这种情况下,由于没有找到 MongoTemplate 类型的 bean,因此自动配置介入并配置了一个。
在 negativeMatches 下,Spring Boot 自动配置考虑配置一个 DispatcherServlet。但是 @ConditionalOnClass 条件注解失败了,因为找不到 DispatcherServlet。
最后,如 unconditionalClasses 部分所示,配置了 ConfigurationPropertiesAutoConfiguration bean。配置属性是 Spring Boot 运行的基础,因此任何与配置属性相关的配置,都应该在没有任何条件的情况下自动配置。
检查环境和配置属性
除了了解您的应用程序 bean 如何连接在一起之外,您可能还对了解哪些环境属性可用,以及哪些配置属性注入了 bean 中感兴趣。
当您向 /env
端点发出 GET 请求时,您将收到一个相当长的,来自 Spring 应用程序正在运行的,所有属性来源的属性列表。这包括来自环境变量的属性、JVM 系统属性、application.properties
和 application.yml
文件,甚至 Spring Cloud Config Server(如果应用程序是 Config Server 的客户端)。
下面的清单显示了,您可能从 /env
端点获得的响应数据的一个大大简化的示例,让您对它提供的信息有所了解。
清单 15.1 来自 /env 端点的数据
$ curl localhost:8081/actuator/env
{
"activeProfiles": [
"development"
],
"propertySources": [
...
{
"name": "systemEnvironment",
"properties": {
"PATH": {
"value": "/usr/bin:/bin:/usr/sbin:/sbin",
"origin": "System Environment Property \"PATH\""
},
...
"HOME": {
"value": "/Users/habuma",
"origin": "System Environment Property \"HOME\""
}
}
},
{
"name": "applicationConfig: [classpath:/application.yml]",
"properties": {
"spring.application.name": {
"value": "ingredient-service",
"origin": "class path resource [application.yml]:3:11"
},
"server.port": {
"value": 8081,
"origin": "class path resource [application.yml]:9:9"
},
...
}
},
...
]
}
尽管 /env
的完整响应提供了更多信息,但清单 15.1 中包含了那些需要关注的元素。首先,请注意响应顶部是一个名为 activeProfiles 的字段。现在的配置表明 development 配置文件处于活动状态。 如果任何其他配置文件处于活动状态,也将列出这些配置文件。
接下来,propertySources 字段是一个数组,其中包含 Spring 应用程序环境中每个属性源的条目。在清单 15.1 中,只显示了 systemEnvironment 和引用 application.yml 文件的 applicationConfig 属性源。
在每个属性源中,列出了该源提供的所有属性,并与其值配对。在 application.yml 属性源的情况下,每个属性的 origin 字段准确说明属性设置的位置,包括在 application.yml 中的行和列。
当该属性的名称作为路径的第二个元素给出时,/env
端点还可用于获取特定属性。例如,要检查 server.port 属性,请提交对 /env/server.port
的 GET 请求,如下所示:
$ curl localhost:8081/actuator/env/server.port
{
"property": {
"source": "systemEnvironment", "value": "8081"
},
"activeProfiles": [ "development" ],
"propertySources": [
{ "name": "server.ports" },
{ "name": "mongo.ports" },
{ "name": "systemProperties" },
{
"name": "systemEnvironment",
"property": {
"value": "8081",
"origin": "System Environment Property \"SERVER_PORT\""
}
},
{ "name": "random" },
{
"name": "applicationConfig: [classpath:/application.yml]",
"property": {
"value": 0,
"origin": "class path resource [application.yml]:9:9"
}
},
{ "name": "springCloudClientHostInfo" },
{ "name": "refresh" },
{ "name": "defaultProperties" },
{ "name": "Management Server" }
]
}
如您所见,所有属性源仍被表示,但只有那些设置了指定属性的源才会包含附加信息。在这种情况下,系统环境属性源和 application.yml 属性源都具有 server.port
属性的值。因为 systemEnvironment 属性源优先于它下面列出的任何属性源,所以它的值 8081 胜出。获胜值反映在属性字段下方的顶部附近。
/env
端点不仅可以用于读取属性值。通过向 /env 端点提交 POST 请求以及带有名称和值字段的 JSON 数据,您还可以在正在运行的应用程序中设置属性。例如,要将名为 tacocloud.discount.code
的属性设置为 TACOS1234,您可以使用 curl 在命令行提交 POST 请求,如下所示:
$ curl localhost:8081/actuator/env \
-d'{"name":"tacocloud.discount.code","value":"TACOS1234"}' \
-H "Content-type: application/json"
{"tacocloud.discount.code":"TACOS1234"}
提交属性后,新设置的属性及其值将在响应中返回。稍后,如果您决定不再需要该属性,您可以向 /env
端点提交 DELETE 请求,以删除通过该端点创建的所有属性:
$ curl localhost:8081/actuator/env -X DELETE
{"tacocloud.discount.code":"TACOS1234"}
与通过 Actuator 的 API 设置属性一样重要,要注意,使用 /env
端点的 POST 请求设置的任何属性,仅适用于接收请求的应用程序实例,是临时的,并且会在应用程序重新启动时丢失.
浏览 HTTP 请求映射
尽管 Spring MVC(和 Spring WebFlux 的)编程模型,通过简单地使用请求映射注释,对方法进行注释来轻松处理 HTTP 请求,但有时很难全面了解,应用程序可以处理的所有类型的 HTTP 请求,以及处理这些请求的组件类型。
Actuator 的 /mappings
端点提供了应用程序中每个 HTTP 请求处理程序的一站式视图,无论是来自 Spring MVC 控制器还是 Actuator 自己的端点之一。要获取 Spring Boot 应用程序中所有端点的完整列表,请向 /mappings
端点发出 GET 请求,您可能会收到类似于下面显示的简化响应的内容。
清单 15.2 如 /mappings 端点所示的 HTTP 请求映射
$ curl localhost:8081/actuator/mappings | jq
{
"contexts": {
"application-1": {
"mappings": {
"dispatcherHandlers": {
"webHandler": [
...
{
"predicate": "{[/ingredients],methods=[GET]}",
"handler": "public
reactor.core.publisher.Flux<tacos.ingredients.Ingredient>
tacos.ingredients.IngredientsController.allIngredients()",
"details": {
"handlerMethod": {
"className": "tacos.ingredients.IngredientsController",
"name": "allIngredients",
"descriptor": "()Lreactor/core/publisher/Flux;"
},
"handlerFunction": null,
"requestMappingConditions": {
"consumes": [],
"headers": [],
"methods": [
"GET"
],
"params": [],
"patterns": [
"/ingredients"
],
"produces": []
}
}
},
...
]
}
},
"parentId": "application-1"
},
"bootstrap": {
"mappings": {
"dispatcherHandlers": {}
},
"parentId": null
}
}
}
在这里,来自命令 curl 的响应通过管道传输到一个名为 jq 的解析器中,以更美观易读的方式打印 JSON 数据。为简洁起见,此响应已被删节以仅显示单个请求处理程序。具体来说,它表明对 /ingredients
的 GET 请求将由 IngredientsController 的 allIngredients()
方法处理。
管理日志级别
日志记录对任何应用程序来说都是非常重要的功能。日志记录可以提供一种审计手段,以及一种粗略的调试手段。
设置日志记录级别是需要进行反复权衡的行为。如果日志级别设置得低,日志中可能会出现过多的噪音,可能很难找到有用的信息。另一方面,如果您将日志记录级别设置得太高,则日志对于了解应用程序正在执行的操作可能没有多大价值。
日志级别通常应用在包级别上。如果您想知道正在运行的 Spring Boot 应用程序中设置了哪些日志记录级别,您可以向 /loggers
端点发出 GET 请求。以下 JSON 显示了对 /loggers
的响应的摘录:
{
"levels": [ "OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" ],
"loggers": {
"ROOT": {
"configuredLevel": "INFO", "effectiveLevel": "INFO"
},
...
"org.springframework.web": {
"configuredLevel": null, "effectiveLevel": "INFO"
},
...
"tacos": {
"configuredLevel": null, "effectiveLevel": "INFO"
},
"tacos.ingredients": {
"configuredLevel": null, "effectiveLevel": "INFO"
},
"tacos.ingredients.IngredientServiceApplication": {
"configuredLevel": null, "effectiveLevel": "INFO"
}
}
}
响应数据以所有有效日志记录级别的列表开始。之后,loggers 元素会列出应用程序中每个包的日志记录级别的详细信息。 configureLevel 属性显示已显式配置的日志记录级别(如果尚未显式配置,则为 null)。 EffectiveLevel 属性给出了有效的日志级别,它可能是从父包或根记录器继承的。
此示例仅显示了根记录器和四个包的日志记录级别,完整的响应会包括应用程序中每个包的日志记录级别条目,包含所有使用到的库中的包。如果您希望查看特定包,您可以将包名称指定为请求路径中的一部分。
例如,如果您只想知道为 tacocloud.ingredients 设置了哪些日志记录级别。您可以向 /loggers/tacos.ingredients
发出请求:
{
"configuredLevel": null,
"effectiveLevel": "INFO"
}
除了返回应用程序包的日志级别外,/loggers
端点还允许您通过发出 POST 请求来更改配置的日志级别。例如,假设您要将 tacocloud.ingredients
包的日志记录级别设置为 DEBUG。用以下 curl 命令将实现这一点:
$ curl localhost:8081/actuator/loggers/tacos/ingredients \
-d'{"configuredLevel":"DEBUG"}' \
-H"Content-type: application/json"
现在日志级别已更改,您可以向 /loggers/tacos/ingredients
发出 GET 请求以查看更改:
{
"configuredLevel": "DEBUG",
"effectiveLevel": "DEBUG"
}
请注意,configuredLevel 以前为 null,现在是 DEBUG。这种变化也传递到了 effectiveLevel。但最重要的是,如果该包中的任何代码在调试级别记录任何内容,日志文件将包含该调试级别信息。