16.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.propertiesapplication.yml 文件,甚至 Spring Cloud Config Server(如果应用程序是 Config Server 的客户端)。

下面的清单显示了,您可能从 /env 端点获得的响应数据的一个大大简化的示例,让您对它提供的信息有所了解。

清单 16.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 的完整响应提供了更多信息,但清单 16.1 中包含了那些需要关注的元素。首先,请注意响应顶部是一个名为 activeProfiles 的字段。现在的配置表明 development 配置文件处于活动状态。 如果任何其他配置文件处于活动状态,也将列出这些配置文件。

接下来,propertySources 字段是一个数组,其中包含 Spring 应用程序环境中每个属性源的条目。在清单 16.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 请求,您可能会收到类似于下面显示的简化响应的内容。

清单 16.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
      }
    }
}

为简洁起见,此响应已被删节以仅显示单个请求处理程序。具体来说,它表明对 /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。但最重要的是,如果该包中的任何代码在调试级别记录任何内容,日志文件将包含该调试级别信息。

最后更新于