(window.webpackJsonp=window.webpackJsonp||[]).push([[395],{835:function(e,t,a){"use strict";a.r(t);var r=a(56),v=Object(r.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"可投入生产的功能"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#可投入生产的功能"}},[e._v("#")]),e._v(" 可投入生产的功能")]),e._v(" "),a("p",[e._v("Spring 启动包括许多额外的功能,以帮助你在将应用程序推向生产时监视和管理该应用程序。你可以选择通过使用 HTTP 端点或使用 JMX 来管理和监视你的应用程序。审核、健康和度量收集也可以自动应用到你的应用程序中。")]),e._v(" "),a("h2",{attrs:{id:"_1-启用可用于生产的功能"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-启用可用于生产的功能"}},[e._v("#")]),e._v(" 1. 启用可用于生产的功能")]),e._v(" "),a("p",[e._v("["),a("code",[e._v("spring-boot-actuator")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator)模块提供了 Spring boot 的所有生产就绪功能。推荐的启用这些特性的方法是添加对"),a("code",[e._v("spring-boot-starter-actuator")]),e._v("“starter”的依赖关系。")]),e._v(" "),a("p",[e._v("执行器的定义")]),e._v(" "),a("p",[e._v("执行器是一个制造术语,指用于移动或控制某物的机械设备。执行器可以从微小的变化中产生大量的运动。")]),e._v(" "),a("p",[e._v("要将执行器添加到基于 Maven 的项目中,请添加以下“starter”依赖项:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("\n \n org.springframework.boot\n spring-boot-starter-actuator\n \n\n")])])]),a("p",[e._v("对于 Gradle,使用以下声明:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("dependencies {\n implementation 'org.springframework.boot:spring-boot-starter-actuator'\n}\n")])])]),a("h2",{attrs:{id:"_2-端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-端点"}},[e._v("#")]),e._v(" 2. 端点")]),e._v(" "),a("p",[e._v("执行器端点允许你监视应用程序并与其交互。 Spring 启动包括许多内置的端点,并允许你添加自己的端点。例如,"),a("code",[e._v("health")]),e._v("端点提供了基本的应用程序健康信息。")]),e._v(" "),a("p",[e._v("你可以"),a("a",{attrs:{href:"#actuator.endpoints.enabling"}},[e._v("启用或禁用")]),e._v("每个单独的端点和"),a("a",{attrs:{href:"#actuator.endpoints.exposing"}},[e._v("通过 HTTP 或 JMX 公开它们(使它们可以远程访问)")]),e._v("。当端点被启用和公开时,它被认为是可用的。内置端点只有在可用时才会自动配置。大多数应用程序选择的是公开而不是 HTTP,在 HTTP 中,端点的 ID 和"),a("code",[e._v("/actuator")]),e._v("的前缀被映射到一个 URL。例如,默认情况下,"),a("code",[e._v("health")]),e._v("端点映射到"),a("code",[e._v("/actuator/health")]),e._v("。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("要了解有关执行器端点及其请求和响应格式的更多信息,请参见单独的 API 文档("),a("a",{attrs:{href:"https://docs.spring.io/spring-boot/docs/2.6.4/actuator-api/htmlsingle",target:"_blank",rel:"noopener noreferrer"}},[e._v("HTML"),a("OutboundLink")],1),e._v("或"),a("a",{attrs:{href:"https://docs.spring.io/spring-boot/docs/2.6.4/actuator-api/pdf/spring-boot-actuator-web-api.pdf",target:"_blank",rel:"noopener noreferrer"}},[e._v("PDF"),a("OutboundLink")],1),e._v(")。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("以下是与技术无关的端点:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("ID")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("auditevents")])]),e._v(" "),a("td",[e._v("公开当前应用程序的审计事件信息。"),a("br"),e._v("需要"),a("code",[e._v("AuditEventRepository")]),e._v(" Bean。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("beans")])]),e._v(" "),a("td",[e._v("显示应用程序中所有 Spring bean 的完整列表。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("caches")])]),e._v(" "),a("td",[e._v("公开可用的缓存。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("conditions")])]),e._v(" "),a("td",[e._v("显示在配置和自动配置类上评估的条件,以及它们匹配或不匹配的原因。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("configprops")])]),e._v(" "),a("td",[e._v("显示所有"),a("code",[e._v("@Configuration属性")]),e._v("的已整理列表。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("env")])]),e._v(" "),a("td",[e._v("公开 Spring 的"),a("code",[e._v("ConfigurableEnvironment")]),e._v("中的属性。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("flyway")])]),e._v(" "),a("td",[e._v("显示已应用的任何 Flyway 数据库迁移。"),a("br"),e._v("需要一个或多个"),a("code",[e._v("Flyway")]),e._v("bean。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("health")])]),e._v(" "),a("td",[e._v("显示应用程序的健康信息。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("httptrace")])]),e._v(" "),a("td",[e._v("显示 HTTP 跟踪信息(默认情况下,最近 100 次 HTTP 请求-响应交换)。"),a("br"),e._v("需要"),a("code",[e._v("HttpTraceRepository")]),e._v(" Bean。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("info")])]),e._v(" "),a("td",[e._v("显示任意的应用程序信息。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("integrationgraph")])]),e._v(" "),a("td",[e._v("显示 Spring 积分图。"),a("br"),e._v("需要对"),a("code",[e._v("spring-integration-core")]),e._v("的依赖关系。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("loggers")])]),e._v(" "),a("td",[e._v("显示并修改应用程序中记录器的配置。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("liquibase")])]),e._v(" "),a("td",[e._v("显示已应用的任何 Liquibase 数据库迁移。"),a("br"),e._v("需要一个或多个"),a("code",[e._v("Liquibase")]),e._v("bean。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("metrics")])]),e._v(" "),a("td",[e._v("显示当前应用程序的“度量”信息。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("mappings")])]),e._v(" "),a("td",[e._v("显示所有"),a("code",[e._v("@RequestMapping")]),e._v("路径的已整理列表。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("quartz")])]),e._v(" "),a("td",[e._v("显示有关 Quartz 调度程序作业的信息。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("scheduledtasks")])]),e._v(" "),a("td",[e._v("显示应用程序中的计划任务。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("sessions")])]),e._v(" "),a("td",[e._v("允许从 Spring 会话支持的会话存储中检索和删除用户会话。"),a("br"),e._v("需要使用 Spring 会话的基于 Servlet 的 Web 应用程序。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("shutdown")])]),e._v(" "),a("td",[e._v("让应用程序优雅地关闭。"),a("br"),e._v("默认禁用。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("startup")])]),e._v(" "),a("td",[e._v("显示由"),a("code",[e._v("ApplicationStartup")]),e._v("收集的"),a("RouterLink",{attrs:{to:"/spring-boot/features.html#features.spring-application.startup-tracking"}},[e._v("启动步骤数据")]),e._v("。"),a("br"),e._v("需要将"),a("code",[e._v("SpringApplication")]),e._v("配置为"),a("code",[e._v("BufferingApplicationStartup")]),e._v("。")],1)]),e._v(" "),a("tr",[a("td",[a("code",[e._v("threaddump")])]),e._v(" "),a("td",[e._v("执行线程转储。")])])])]),e._v(" "),a("p",[e._v("如果你的应用程序是一个 Web 应用程序( Spring MVC、 Spring WebFlux 或 Jersey),则可以使用以下附加端点:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("ID")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("heapdump")])]),e._v(" "),a("td",[e._v("返回堆转储文件。"),a("br"),e._v("在热点 JVM 上,将返回一个"),a("code",[e._v("HPROF")]),e._v("-format 文件。"),a("br"),e._v("在 OpenJ9JVM 上,将返回一个"),a("code",[e._v("PHD")]),e._v("-format 文件。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("jolokia")])]),e._v(" "),a("td",[e._v("当 Jolokia 在 Classpath 上时,在 HTTP 上公开 JMX Bean(WebFlux 不可用)。"),a("br"),e._v("需要依赖于"),a("code",[e._v("jolokia-core")]),e._v("。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("logfile")])]),e._v(" "),a("td",[e._v("返回日志文件的内容(如果设置了"),a("code",[e._v("logging.file.name")]),e._v("或"),a("code",[e._v("logging.file.path")]),e._v("属性)。"),a("br"),e._v("支持使用 http"),a("code",[e._v("Range")]),e._v("头来检索日志文件的部分内容。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("prometheus")])]),e._v(" "),a("td",[e._v("以 Prometheus 服务器可以抓取的格式公开度量数据。"),a("br"),e._v("需要对"),a("code",[e._v("micrometer-registry-prometheus")]),e._v("具有依赖关系。")])])])]),e._v(" "),a("h3",{attrs:{id:"_2-1-启用端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-启用端点"}},[e._v("#")]),e._v(" 2.1.启用端点")]),e._v(" "),a("p",[e._v("默认情况下,除了"),a("code",[e._v("shutdown")]),e._v("之外的所有端点都已启用。要配置端点的启用,请使用其"),a("code",[e._v("management.endpoint..enabled")]),e._v("属性。下面的示例启用"),a("code",[e._v("shutdown")]),e._v("端点:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoint.shutdown.enabled=true\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n endpoint:\n shutdown:\n enabled: true\n")])])]),a("p",[e._v("如果你希望端点使能是 OPT 输入而不是 OPT 输出,那么将"),a("code",[e._v("management.endpoints.enabled-by-default")]),e._v("属性设置为"),a("code",[e._v("false")]),e._v(",并使用单独的端点"),a("code",[e._v("enabled")]),e._v("属性来 OPT 返回。下面的示例启用"),a("code",[e._v("info")]),e._v("端点并禁用所有其他端点:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.enabled-by-default=false\nmanagement.endpoint.info.enabled=true\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n endpoints:\n enabled-by-default: false\n endpoint:\n info:\n enabled: true\n")])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("已禁用的端点将从应用程序上下文中完全删除。"),a("br"),e._v("如果只想更改公开端点的技术,请使用["),a("code",[e._v("include")]),e._v("和"),a("code",[e._v("exclude")]),e._v("属性](#actuator.endpoints.explosing)。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"_2-2-公开端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-公开端点"}},[e._v("#")]),e._v(" 2.2.公开端点")]),e._v(" "),a("p",[e._v("由于端点可能包含敏感信息,因此你应该仔细考虑何时公开它们。下表显示了内建端点的默认暴露:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("ID")]),e._v(" "),a("th",[e._v("JMX")]),e._v(" "),a("th",[e._v("Web")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("auditevents")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("beans")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("caches")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("conditions")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("configprops")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("env")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("flyway")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("health")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("Yes")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("heapdump")])]),e._v(" "),a("td",[e._v("N/A")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("httptrace")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("info")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("integrationgraph")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("jolokia")])]),e._v(" "),a("td",[e._v("N/A")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("logfile")])]),e._v(" "),a("td",[e._v("N/A")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("loggers")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("liquibase")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("metrics")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("mappings")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("prometheus")])]),e._v(" "),a("td",[e._v("N/A")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("quartz")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("scheduledtasks")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("sessions")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("shutdown")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("startup")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("threaddump")])]),e._v(" "),a("td",[e._v("Yes")]),e._v(" "),a("td",[e._v("No")])])])]),e._v(" "),a("p",[e._v("要更改暴露的端点,请使用以下特定于技术的"),a("code",[e._v("include")]),e._v("和"),a("code",[e._v("exclude")]),e._v("属性:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("财产")]),e._v(" "),a("th",[e._v("Default")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("management.endpoints.jmx.exposure.exclude")])]),e._v(" "),a("td")]),e._v(" "),a("tr",[a("td",[a("code",[e._v("management.endpoints.jmx.exposure.include")])]),e._v(" "),a("td",[a("code",[e._v("*")])])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("management.endpoints.web.exposure.exclude")])]),e._v(" "),a("td")]),e._v(" "),a("tr",[a("td",[a("code",[e._v("management.endpoints.web.exposure.include")])]),e._v(" "),a("td",[a("code",[e._v("health")])])])])]),e._v(" "),a("p",[a("code",[e._v("include")]),e._v("属性列出了公开的端点的 ID。"),a("code",[e._v("exclude")]),e._v("属性列出了不应该公开的端点的 ID。"),a("code",[e._v("exclude")]),e._v("属性优先于"),a("code",[e._v("include")]),e._v("属性。你可以使用端点 ID 列表来配置"),a("code",[e._v("include")]),e._v("和"),a("code",[e._v("exclude")]),e._v("属性。")]),e._v(" "),a("p",[e._v("例如,要停止在 JMX 上公开所有端点,而只公开"),a("code",[e._v("health")]),e._v("和"),a("code",[e._v("info")]),e._v("端点,请使用以下属性:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.jmx.exposure.include=health,info\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoints:\n jmx:\n exposure:\n include: "health,info"\n')])])]),a("p",[a("code",[e._v("*")]),e._v("可用于选择所有端点。例如,要在 HTTP 上公开除了"),a("code",[e._v("env")]),e._v("和"),a("code",[e._v("beans")]),e._v("端点之外的所有内容,请使用以下属性:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.web.exposure.include=*\nmanagement.endpoints.web.exposure.exclude=env,beans\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoints:\n web:\n exposure:\n include: "*"\n exclude: "env,beans"\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[a("code",[e._v("*")]),e._v("在 YAML 中具有特殊的含义,因此,如果你想包含(或排除)所有端点,请务必添加引号。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果你的应用程序公开,我们强烈建议你也"),a("a",{attrs:{href:"#actuator.endpoints.security"}},[e._v("保护你的端点")]),e._v("。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果你希望实现自己的端点公开策略,则可以注册"),a("code",[e._v("EndpointFilter")]),e._v(" Bean。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"_2-3-安全"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-安全"}},[e._v("#")]),e._v(" 2.3.安全")]),e._v(" "),a("p",[e._v("出于安全目的,除"),a("code",[e._v("/health")]),e._v("以外的所有执行器都默认禁用。你可以使用"),a("code",[e._v("management.endpoints.web.exposure.include")]),e._v("属性来启用执行器。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("在设置"),a("code",[e._v("management.endpoints.web.exposure.include")]),e._v("之前,请确保暴露的执行器不包含敏感信息,通过将它们放置在防火墙后面来进行安全保护,或者通过 Spring 之类的安全性来进行安全保护。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("如果 Spring 安全性在 Classpath 上,并且不存在其他"),a("code",[e._v("WebSecurityConfigurerAdapter")]),e._v("或"),a("code",[e._v("SecurityFilterChain")]),e._v(" Bean,则除"),a("code",[e._v("/health")]),e._v("以外的所有致动器都由 Spring 引导自动配置来保护。如果你定义了自定义的"),a("code",[e._v("WebSecurityConfigurerAdapter")]),e._v("或"),a("code",[e._v("SecurityFilterChain")]),e._v(" Bean, Spring 引导自动配置就会后退,并允许你完全控制执行器访问规则。")]),e._v(" "),a("p",[e._v("如果你希望为 HTTP 端点配置自定义安全性(例如,仅允许具有特定角色的用户访问它们), Spring Boot 提供了一些方便的"),a("code",[e._v("RequestMatcher")]),e._v("对象,你可以将这些对象与 Spring 安全性结合使用。")]),e._v(" "),a("p",[e._v("典型的 Spring 安全配置可能类似于以下示例:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration(proxyBeanMethods = false)\npublic class MySecurityConfiguration {\n\n @Bean\n public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n http.requestMatcher(EndpointRequest.toAnyEndpoint())\n .authorizeRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"));\n http.httpBasic();\n return http.build();\n }\n\n}\n\n')])])]),a("p",[e._v("前面的示例使用"),a("code",[e._v("EndpointRequest.toAnyEndpoint()")]),e._v("将请求匹配到任何端点,然后确保所有请求都具有"),a("code",[e._v("ENDPOINT_ADMIN")]),e._v("角色。在"),a("code",[e._v("EndpointRequest")]),e._v("上也可以使用其他几种匹配方法。有关详细信息,请参见 API 文档("),a("a",{attrs:{href:"https://docs.spring.io/spring-boot/docs/2.6.4/actuator-api/htmlsingle",target:"_blank",rel:"noopener noreferrer"}},[e._v("HTML"),a("OutboundLink")],1),e._v("或"),a("a",{attrs:{href:"https://docs.spring.io/spring-boot/docs/2.6.4/actuator-api/pdf/spring-boot-actuator-web-api.pdf",target:"_blank",rel:"noopener noreferrer"}},[e._v("PDF"),a("OutboundLink")],1),e._v(")。")]),e._v(" "),a("p",[e._v("如果你将应用程序部署在防火墙之后,那么你可能希望你的所有执行器端点都可以访问,而无需进行身份验证。你可以通过更改"),a("code",[e._v("management.endpoints.web.exposure.include")]),e._v("属性来实现此目的,如下所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.web.exposure.include=*\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoints:\n web:\n exposure:\n include: "*"\n')])])]),a("p",[e._v("此外,如果存在 Spring 安全性,则需要添加自定义安全配置,该配置允许对端点进行未经身份验证的访问,如下例所示:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration(proxyBeanMethods = false)\npublic class MySecurityConfiguration {\n\n @Bean\n public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n http.requestMatcher(EndpointRequest.toAnyEndpoint())\n .authorizeRequests((requests) -> requests.anyRequest().permitAll());\n return http.build();\n }\n\n}\n\n")])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("在上述两个示例中,配置仅适用于执行器端点。"),a("br"),e._v("由于 Spring boot 的安全配置在存在任何"),a("code",[e._v("SecurityFilterChain")]),e._v(" Bean 的情况下完全退缩,因此需要配置一个附加的"),a("code",[e._v("SecurityFilterChain")]),e._v(" Bean,其规则适用于应用程序的其余部分。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_2-3-1-跨站点请求伪造保护"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-1-跨站点请求伪造保护"}},[e._v("#")]),e._v(" 2.3.1.跨站点请求伪造保护")]),e._v(" "),a("p",[e._v("由于 Spring boot 依赖于 Spring Security 的默认值,因此 CSRF 保护在默认情况下是打开的。这意味着要求执行器端点"),a("code",[e._v("POST")]),e._v("(关机和记录器端点)、"),a("code",[e._v("PUT")]),e._v("或"),a("code",[e._v("DELETE")]),e._v("的端点在使用默认安全配置时会得到 403(禁止)错误。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("我们建议仅当你正在创建一个由非浏览器客户端使用的服务时,才完全禁用 CSRF 保护。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("你可以在"),a("a",{attrs:{href:"https://docs.spring.io/spring-security/reference/5.6.2/features/exploits/csrf.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Spring Security Reference Guide"),a("OutboundLink")],1),e._v("中找到有关 CSRF 保护的其他信息。")]),e._v(" "),a("h3",{attrs:{id:"_2-4-配置端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-配置端点"}},[e._v("#")]),e._v(" 2.4.配置端点")]),e._v(" "),a("p",[e._v("端点自动缓存响应,以读取不接受任何参数的操作。要配置端点缓存响应的时间长度,请使用其"),a("code",[e._v("cache.time-to-live")]),e._v("属性。下面的示例将"),a("code",[e._v("beans")]),e._v("端点缓存的持续时间设置为 10 秒:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoint.beans.cache.time-to-live=10s\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoint:\n beans:\n cache:\n time-to-live: "10s"\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[a("code",[e._v("management.endpoint.")]),e._v("前缀唯一地标识正在配置的端点。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"_2-5-用于执行器-web-端点的超媒体"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-5-用于执行器-web-端点的超媒体"}},[e._v("#")]),e._v(" 2.5.用于执行器 Web 端点的超媒体")]),e._v(" "),a("p",[e._v("添加了一个“发现页面”,其中包含指向所有端点的链接。默认情况下,“发现页面”在"),a("code",[e._v("/actuator")]),e._v("上可用。")]),e._v(" "),a("p",[e._v("要禁用“发现页面”,请将以下属性添加到应用程序属性中:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.web.discovery.enabled=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n endpoints:\n web:\n discovery:\n enabled: false\n")])])]),a("p",[e._v("在配置自定义管理上下文路径时,“发现页”会自动从"),a("code",[e._v("/actuator")]),e._v("移动到管理上下文的根。例如,如果管理上下文路径是"),a("code",[e._v("/management")]),e._v(",则可以从"),a("code",[e._v("/management")]),e._v("获取发现页面。当管理上下文路径设置为"),a("code",[e._v("/")]),e._v("时,将禁用发现页,以防止与其他映射发生冲突的可能性。")]),e._v(" "),a("h3",{attrs:{id:"_2-6-cors-支持"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-6-cors-支持"}},[e._v("#")]),e._v(" 2.6.CORS 支持")]),e._v(" "),a("p",[a("a",{attrs:{href:"https://en.wikipedia.org/wiki/Cross-origin_resource_sharing",target:"_blank",rel:"noopener noreferrer"}},[e._v("跨源资源共享"),a("OutboundLink")],1),e._v("是一个"),a("a",{attrs:{href:"https://www.w3.org/TR/cors/",target:"_blank",rel:"noopener noreferrer"}},[e._v("W3C 规范"),a("OutboundLink")],1),e._v(",它允许你以灵活的方式指定授权哪种类型的跨域请求。如果使用 Spring MVC 或 Spring WebFlux,则可以配置 Actuator 的 Web 端点以支持此类场景。")]),e._v(" "),a("p",[e._v("默认情况下,CORS 支持是禁用的,并且只有在你设置了"),a("code",[e._v("management.endpoints.web.cors.allowed-origins")]),e._v("属性后才会启用。以下配置允许"),a("code",[e._v("GET")]),e._v("和"),a("code",[e._v("POST")]),e._v("来自"),a("code",[e._v("example.com")]),e._v("域的调用:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.web.cors.allowed-origins=https://example.com\nmanagement.endpoints.web.cors.allowed-methods=GET,POST\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoints:\n web:\n cors:\n allowed-origins: "https://example.com"\n allowed-methods: "GET,POST"\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("参见["),a("code",[e._v("CorsEndpoint属性")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator-autofigure/SRC/main/java/org/springframework/boot/actuate/autofigure/endpoint/web/corsendpointproperties.java)以获取完整的选项列表。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"_2-7-实现自定义端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-7-实现自定义端点"}},[e._v("#")]),e._v(" 2.7.实现自定义端点")]),e._v(" "),a("p",[e._v("如果添加带有"),a("code",[e._v("@Bean")]),e._v("注释的"),a("code",[e._v("@Endpoint")]),e._v(",则任何带有"),a("code",[e._v("@ReadOperation")]),e._v("、"),a("code",[e._v("@WriteOperation")]),e._v("或"),a("code",[e._v("@DeleteOperation")]),e._v("注释的方法都会在 JMX 上自动公开,在 Web 应用程序中,也会在 HTTP 上自动公开。可以通过使用 Jersey、 Spring MVC 或 Spring WebFlux 在 HTTP 上公开端点。如果球衣和 Spring MVC 都可用,则使用 Spring MVC。")]),e._v(" "),a("p",[e._v("下面的示例公开了一个返回自定义对象的读取操作:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('@ReadOperation\npublic CustomData getData() {\n return new CustomData("test", 5);\n}\n\n')])])]),a("p",[e._v("你还可以通过使用"),a("code",[e._v("@JmxEndpoint")]),e._v("或"),a("code",[e._v("@WebEndpoint")]),e._v("来编写特定于技术的端点。这些端点仅限于各自的技术。例如,"),a("code",[e._v("@WebEndpoint")]),e._v("仅在 HTTP 上公开,而不在 JMX 上公开。")]),e._v(" "),a("p",[e._v("你可以使用"),a("code",[e._v("@EndpointWebExtension")]),e._v("和"),a("code",[e._v("@EndpointJmxExtension")]),e._v("来编写特定于技术的扩展。这些注释允许你提供特定于技术的操作,以增强现有的端点。")]),e._v(" "),a("p",[e._v("最后,如果需要访问特定于 Web Framework 的功能,则可以实现 Servlet 或 Spring "),a("code",[e._v("@Controller")]),e._v("和"),a("code",[e._v("@RestController")]),e._v("端点,但代价是它们不能在 JMX 上或在使用不同的 Web 框架时可用。")]),e._v(" "),a("h4",{attrs:{id:"_2-7-1-接收输入"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-7-1-接收输入"}},[e._v("#")]),e._v(" 2.7.1.接收输入")]),e._v(" "),a("p",[e._v("端点上的操作通过其参数接收输入。当在 Web 上公开时,这些参数的值来自 URL 的查询参数和 JSON 请求主体。当通过 JMX 公开时,参数将映射到 MBean 操作的参数。默认情况下需要参数。可以通过使用"),a("code",[e._v("@javax.annotation.Nullable")]),e._v("或"),a("code",[e._v("@org.springframework.lang.Nullable")]),e._v("对它们进行注释来使它们成为可选的。")]),e._v(" "),a("p",[e._v("你可以将 JSON 请求主体中的每个根属性映射到端点的参数。考虑以下 JSON 请求主体:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('{\n "name": "test",\n "counter": 42\n}\n')])])]),a("p",[e._v("你可以使用它来调用一个包含"),a("code",[e._v("String name")]),e._v("和"),a("code",[e._v("int counter")]),e._v("参数的写操作,如下例所示:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('@WriteOperation\npublic void updateData(String name, int counter) {\n // injects "test" and 42\n}\n\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("由于端点与技术无关,因此只能在方法签名中指定简单的类型。"),a("br"),e._v("特别是,声明带有"),a("code",[e._v("CustomData")]),e._v("类型的单个参数,该类型定义了"),a("code",[e._v("name")]),e._v("和"),a("code",[e._v("counter")]),e._v("属性,不受支持。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("为了让输入映射到操作方法的参数,实现端点的 Java 代码应该使用"),a("code",[e._v("-parameters")]),e._v("进行编译,实现端点的代码应该用"),a("code",[e._v("-java-parameters")]),e._v("编译。"),a("br"),e._v("如果你使用 Spring boot 的 Gradle 插件,或者如果你使用 Maven 和"),a("code",[e._v("spring-boot-starter-parent")]),e._v(",这将自动发生。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h5",{attrs:{id:"输入类型转换"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#输入类型转换"}},[e._v("#")]),e._v(" 输入类型转换")]),e._v(" "),a("p",[e._v("如果需要,将传递给端点操作方法的参数自动转换为所需的类型。在调用操作方法之前,通过使用"),a("code",[e._v("ApplicationConversionService")]),e._v("的实例以及"),a("code",[e._v("Converter")]),e._v("或"),a("code",[e._v("GenericConverter")]),e._v("的实例,将通过 JMX 或 HTTP 接收的输入转换为所需的类型。")]),e._v(" "),a("h4",{attrs:{id:"_2-7-2-自定义-web-端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-7-2-自定义-web-端点"}},[e._v("#")]),e._v(" 2.7.2.自定义 Web 端点")]),e._v(" "),a("p",[e._v("对"),a("code",[e._v("@Endpoint")]),e._v("、"),a("code",[e._v("@WebEndpoint")]),e._v("或"),a("code",[e._v("@EndpointWebExtension")]),e._v("的操作使用 Jersey、 Spring MVC 或 Spring WebFlux 在 HTTP 上自动公开。如果球衣和 Spring MVC 都可用,则使用 Spring MVC。")]),e._v(" "),a("h5",{attrs:{id:"web-端点请求谓词"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#web-端点请求谓词"}},[e._v("#")]),e._v(" Web 端点请求谓词")]),e._v(" "),a("p",[e._v("对于公开 Web 的端点上的每个操作,都会自动生成一个请求谓词。")]),e._v(" "),a("h5",{attrs:{id:"路径"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#路径"}},[e._v("#")]),e._v(" 路径")]),e._v(" "),a("p",[e._v("谓词的路径由端点的 ID 和公开 Web 的端点的基本路径决定。默认的基本路径是"),a("code",[e._v("/actuator")]),e._v("。例如,ID 为"),a("code",[e._v("sessions")]),e._v("的端点在谓词中使用"),a("code",[e._v("/actuator/sessions")]),e._v("作为其路径。")]),e._v(" "),a("p",[e._v("你可以通过使用"),a("code",[e._v("@Selector")]),e._v("注释操作方法的一个或多个参数来进一步自定义路径。将这样的参数作为路径变量添加到路径谓词中。当调用端点操作时,变量的值被传递到操作方法中。如果要捕获所有剩余的路径元素,可以将"),a("code",[e._v("@Selector(Match=ALL_REMAINING)")]),e._v("添加到最后一个参数,并使其成为与"),a("code",[e._v("String[]")]),e._v("转换兼容的类型。")]),e._v(" "),a("h5",{attrs:{id:"http-方法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-方法"}},[e._v("#")]),e._v(" HTTP 方法")]),e._v(" "),a("p",[e._v("谓词的 HTTP 方法由操作类型决定,如下表所示:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("操作")]),e._v(" "),a("th",[e._v("HTTP method")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("@ReadOperation")])]),e._v(" "),a("td",[a("code",[e._v("GET")])])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("@WriteOperation")])]),e._v(" "),a("td",[a("code",[e._v("POST")])])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("@DeleteOperation")])]),e._v(" "),a("td",[a("code",[e._v("DELETE")])])])])]),e._v(" "),a("h5",{attrs:{id:"消耗"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#消耗"}},[e._v("#")]),e._v(" 消耗")]),e._v(" "),a("p",[e._v("对于使用请求主体的"),a("code",[e._v("@WriteOperation")]),e._v("(http"),a("code",[e._v("POST")]),e._v("),谓词的"),a("code",[e._v("consumes")]),e._v("子句是"),a("code",[e._v("application/vnd.spring-boot.actuator.v2+json, application/json")]),e._v("。对于所有其他操作,"),a("code",[e._v("consumes")]),e._v("子句是空的。")]),e._v(" "),a("h5",{attrs:{id:"生产"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#生产"}},[e._v("#")]),e._v(" 生产")]),e._v(" "),a("p",[e._v("谓词的"),a("code",[e._v("produces")]),e._v("子句可以由"),a("code",[e._v("@DeleteOperation")]),e._v("、"),a("code",[e._v("@ReadOperation")]),e._v("和"),a("code",[e._v("@WriteOperation")]),e._v("注释的"),a("code",[e._v("produces")]),e._v("属性确定。属性是可选的。如果不使用,则自动确定"),a("code",[e._v("produces")]),e._v("子句。")]),e._v(" "),a("p",[e._v("如果操作方法返回"),a("code",[e._v("void")]),e._v("或"),a("code",[e._v("Void")]),e._v(",则"),a("code",[e._v("produces")]),e._v("子句为空。如果操作方法返回一个"),a("code",[e._v("org.springframework.core.io.Resource")]),e._v(",则"),a("code",[e._v("produces")]),e._v("子句是"),a("code",[e._v("application/octet-stream")]),e._v("。对于所有其他操作,"),a("code",[e._v("produces")]),e._v("子句是"),a("code",[e._v("application/vnd.spring-boot.actuator.v2+json, application/json")]),e._v("。")]),e._v(" "),a("h5",{attrs:{id:"web-端点响应状态"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#web-端点响应状态"}},[e._v("#")]),e._v(" Web 端点响应状态")]),e._v(" "),a("p",[e._v("端点操作的默认响应状态取决于操作类型(读、写或删除)以及操作返回的内容(如果有的话)。")]),e._v(" "),a("p",[e._v("如果"),a("code",[e._v("@ReadOperation")]),e._v("返回一个值,则响应状态将为 200(OK)。如果它不返回一个值,响应状态将是 404(未找到)。")]),e._v(" "),a("p",[e._v("如果"),a("code",[e._v("@WriteOperation")]),e._v("或"),a("code",[e._v("@DeleteOperation")]),e._v("返回一个值,则响应状态将为 200(确定)。如果它不返回一个值,响应状态将是 204(没有内容)。")]),e._v(" "),a("p",[e._v("如果调用的操作没有所需的参数或参数不能转换为所需的类型,则不调用该操作方法,响应状态将为 400(错误请求)。")]),e._v(" "),a("h5",{attrs:{id:"web-端点范围请求"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#web-端点范围请求"}},[e._v("#")]),e._v(" Web 端点范围请求")]),e._v(" "),a("p",[e._v("你可以使用 HTTP 范围请求来请求 HTTP 资源的一部分。当使用 Spring MVC 或 Spring Web 流量时,返回"),a("code",[e._v("org.springframework.core.io.Resource")]),e._v("的操作自动支持范围请求。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("使用 Jersey 时不支持范围请求。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h5",{attrs:{id:"web-端点安全"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#web-端点安全"}},[e._v("#")]),e._v(" Web 端点安全")]),e._v(" "),a("p",[e._v("在 Web 端点或特定于 Web 的端点扩展上的操作可以接收当前的"),a("code",[e._v("java.security.Principal")]),e._v("或"),a("code",[e._v("org.springframework.boot.actuate.endpoint.SecurityContext")]),e._v("作为方法参数。前者通常与"),a("code",[e._v("@Nullable")]),e._v("结合使用,以为经过身份验证的和未经身份验证的用户提供不同的行为。后者通常用于通过使用其"),a("code",[e._v("isUserInRole(String)")]),e._v("方法执行授权检查。")]),e._v(" "),a("h4",{attrs:{id:"_2-7-3-servlet-端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-7-3-servlet-端点"}},[e._v("#")]),e._v(" 2.7.3. Servlet 端点")]),e._v(" "),a("p",[e._v("Servlet 可以通过实现一个用"),a("code",[e._v("@ServletEndpoint")]),e._v("注释的类来公开一个端点,该类也实现"),a("code",[e._v("Supplier")]),e._v("。 Servlet 端点提供了与 Servlet 容器的更深的集成,但以牺牲可移植性为代价。它们旨在用于将现有的 Servlet 作为端点公开。对于新的端点,应尽可能使用"),a("code",[e._v("@Endpoint")]),e._v("和"),a("code",[e._v("@WebEndpoint")]),e._v("注释。")]),e._v(" "),a("h4",{attrs:{id:"_2-7-4-控制器端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-7-4-控制器端点"}},[e._v("#")]),e._v(" 2.7.4.控制器端点")]),e._v(" "),a("p",[e._v("可以使用"),a("code",[e._v("@ControllerEndpoint")]),e._v("和"),a("code",[e._v("@RestControllerEndpoint")]),e._v("来实现仅由 Spring MVC 或 Spring WebFlux 公开的端点。方法通过使用 Spring MVC 和 Spring WebFlux 的标准注释进行映射,例如"),a("code",[e._v("@RequestMapping")]),e._v("和"),a("code",[e._v("@GetMapping")]),e._v(",并使用端点的 ID 作为路径的前缀。控制器端点提供了与 Spring 的 Web 框架的更深入集成,但以牺牲可移植性为代价。只要有可能,就应该首选"),a("code",[e._v("@Endpoint")]),e._v("和"),a("code",[e._v("@WebEndpoint")]),e._v("注释。")]),e._v(" "),a("h3",{attrs:{id:"_2-8-健康信息"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-8-健康信息"}},[e._v("#")]),e._v(" 2.8.健康信息")]),e._v(" "),a("p",[e._v("你可以使用健康信息来检查正在运行的应用程序的状态。当生产系统发生故障时,监控软件经常使用它来提醒某人。由"),a("code",[e._v("health")]),e._v("端点公开的信息取决于"),a("code",[e._v("management.endpoint.health.show-details")]),e._v("和"),a("code",[e._v("management.endpoint.health.show-components")]),e._v("属性,这些属性可以配置为以下值之一:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Name")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("never")])]),e._v(" "),a("td",[e._v("细节从未显示。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("when-authorized")])]),e._v(" "),a("td",[e._v("详细信息仅显示给授权用户。"),a("br"),e._v("授权角色可以通过使用"),a("code",[e._v("management.endpoint.health.roles")]),e._v("进行配置。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("always")])]),e._v(" "),a("td",[e._v("详细信息将向所有用户显示。")])])])]),e._v(" "),a("p",[e._v("默认值为"),a("code",[e._v("never")]),e._v("。当用户处于端点的一个或多个角色中时,该用户被视为获得授权。如果端点没有配置的角色(缺省),则所有经过身份验证的用户都被认为是经过授权的。你可以使用"),a("code",[e._v("management.endpoint.health.roles")]),e._v("属性来配置角色。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果你已经保护了你的应用程序,并且希望使用"),a("code",[e._v("always")]),e._v(",那么你的安全配置必须允许经过身份验证的和未经身份验证的用户访问健康端点。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("健康信息是从一个["),a("code",[e._v("HealthContributorRegistry")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/java/org/org/org/org/org/SpringtorFramework/boot/Actuate/health/HealthtorRegistry.java)的内容中收集的(默认情况下,所有[ health() {\n return doHealthCheck().onErrorResume((exception) ->\n Mono.just(new Health.Builder().down(exception).build()));\n }\n\n private Mono doHealthCheck() {\n // perform some specific health check\n return ...\n }\n\n}\n\n")])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("要自动处理该错误,请考虑从"),a("code",[e._v("AbstractReactiveHealthIndicator")]),e._v("扩展。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_2-8-4-自动配置的-reactivehealthindicators"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-8-4-自动配置的-reactivehealthindicators"}},[e._v("#")]),e._v(" 2.8.4.自动配置的 reactivehealthindicators###")]),e._v(" "),a("p",[e._v("在适当的时候, Spring 引导自动配置以下"),a("code",[e._v("ReactiveHealthIndicators")]),e._v(":")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Key")]),e._v(" "),a("th",[e._v("姓名")]),e._v(" "),a("th",[e._v("Description")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("cassandra")])]),e._v(" "),a("td",[e._v("["),a("code",[e._v("CassandraDriverReactiveHealthIndicator")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/org/springframework/boot/actuate/actuate/cassandra/cassandradriverreactivehealthindicator.java)")]),e._v(" "),a("td",[e._v("Checks that a Cassandra database is up.")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("couchbase")])]),e._v(" "),a("td",[e._v("["),a("code",[e._v("CouchbaseReactiveHealthIndicator")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/org/springframework/boot/actuate/actuate/couchbase/couchbase/couchbasereactivehealthindicator.jav")]),e._v(" "),a("td",[e._v("Checks that a Couchbase cluster is up.")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("elasticsearch")])]),e._v(" "),a("td",[e._v("["),a("code",[e._v("ElasticsearchReactiveHealthIndicator")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/org/springframework/boot/actuate/elasticsearch/elasticsearch/elasticsearchreactivehealthindicator.java)")]),e._v(" "),a("td",[e._v("Checks that an Elasticsearch cluster is up.")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("mongo")])]),e._v(" "),a("td",[e._v("["),a("code",[e._v("MongoReactiveHealthIndicator")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/org/springframework/boot/actuate/actuate/mongo/mongoreactivehealthindicator.java)")]),e._v(" "),a("td",[e._v("Checks that a Mongo database is up.")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("neo4j")])]),e._v(" "),a("td",[e._v("["),a("code",[e._v("Neo4jReactiveHealthIndicator")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/org/springframework/boot/actuate/actuate/NEO4j/NEO4jreactivehealthindicator.java)")]),e._v(" "),a("td",[e._v("Checks that a Neo4j database is up.")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("redis")])]),e._v(" "),a("td",[e._v("["),a("code",[e._v("RedisReactiveHealthIndicator")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/org/springframework/boot/actuate/redis/redisreactivehealthindicator.java)")]),e._v(" "),a("td",[e._v("Checks that a Redis server is up.")])])])]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果有必要,用反应性指示器代替常规指示器。"),a("br"),e._v("此外,任何未显式处理的"),a("code",[e._v("HealthIndicator")]),e._v("都会自动包装。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_2-8-5-健康团体"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-8-5-健康团体"}},[e._v("#")]),e._v(" 2.8.5.健康团体")]),e._v(" "),a("p",[e._v("有时,将健康指标组织成可用于不同目的的组是有用的。")]),e._v(" "),a("p",[e._v("要创建健康指示剂组,可以使用"),a("code",[e._v("management.endpoint.health.group.")]),e._v("属性,并将健康指示剂 ID 的列表指定为"),a("code",[e._v("include")]),e._v("或"),a("code",[e._v("exclude")]),e._v("。例如,要创建一个只包含数据库指标的组,你可以定义以下内容:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoint.health.group.custom.include=db\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoint:\n health:\n group:\n custom:\n include: "db"\n')])])]),a("p",[e._v("然后,你可以点击"),a("code",[e._v("[localhost:8080/actuator/health/custom](http://localhost:8080/actuator/health/custom)")]),e._v("检查结果。")]),e._v(" "),a("p",[e._v("类似地,要创建一个从组中排除数据库指标并包括所有其他指标的组,你可以定义以下内容:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoint.health.group.custom.exclude=db\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoint:\n health:\n group:\n custom:\n exclude: "db"\n')])])]),a("p",[e._v("默认情况下,组继承与系统健康相同的"),a("code",[e._v("StatusAggregator")]),e._v("和"),a("code",[e._v("HttpCodeStatusMapper")]),e._v("设置。但是,你也可以在每个组的基础上定义这些。如果需要,还可以重写"),a("code",[e._v("show-details")]),e._v("和"),a("code",[e._v("roles")]),e._v("属性:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoint.health.group.custom.show-details=when-authorized\nmanagement.endpoint.health.group.custom.roles=admin\nmanagement.endpoint.health.group.custom.status.order=fatal,up\nmanagement.endpoint.health.group.custom.status.http-mapping.fatal=500\nmanagement.endpoint.health.group.custom.status.http-mapping.out-of-service=500\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoint:\n health:\n group:\n custom:\n show-details: "when-authorized"\n roles: "admin"\n status:\n order: "fatal,up"\n http-mapping:\n fatal: 500\n out-of-service: 500\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果需要注册自定义"),a("code",[e._v("StatusAggregator")]),e._v("或"),a("code",[e._v("HttpCodeStatusMapper")]),e._v("bean 以用于组,则可以使用"),a("code",[e._v('@Qualifier("groupname")')]),e._v("bean。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("健康组还可以包括/排除"),a("code",[e._v("CompositeHealthContributor")]),e._v("。你也可以只包含/排除"),a("code",[e._v("CompositeHealthContributor")]),e._v("中的某个组件。这可以使用组件的完全限定名称来完成,如下所示:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management.endpoint.health.group.custom.include="test/primary"\nmanagement.endpoint.health.group.custom.exclude="test/primary/b"\n')])])]),a("p",[e._v("在上面的示例中,"),a("code",[e._v("custom")]),e._v("组将包括名为"),a("code",[e._v("HealthContributor")]),e._v("的"),a("code",[e._v("primary")]),e._v(",这是组合"),a("code",[e._v("test")]),e._v("的一个组件。在这里,"),a("code",[e._v("primary")]),e._v("本身是一个组合,而名称为"),a("code",[e._v("b")]),e._v("的"),a("code",[e._v("HealthContributor")]),e._v("将被排除在"),a("code",[e._v("custom")]),e._v("组之外。")]),e._v(" "),a("p",[e._v("可以在主端口或管理端口的附加路径上提供健康组。这在 Kubernetes 等云环境中很有用,在这种环境中,出于安全目的,对执行器端点使用单独的管理端口是很常见的。拥有一个单独的端口可能会导致不可靠的健康检查,因为即使健康检查成功,主应用程序也可能无法正常工作。可以将健康组配置为以下附加路径:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management.endpoint.health.group.live.additional-path="server:/healthz"\n')])])]),a("p",[e._v("这将使"),a("code",[e._v("live")]),e._v("健康组在主服务器端口"),a("code",[e._v("/healthz")]),e._v("上可用。前缀是强制性的,并且必须是"),a("code",[e._v("server:")]),e._v("(表示主服务器端口)或"),a("code",[e._v("management:")]),e._v("(表示管理端口,如果已配置的话。)路径必须是单个路径段。")]),e._v(" "),a("h4",{attrs:{id:"_2-8-6-数据源健康"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-8-6-数据源健康"}},[e._v("#")]),e._v(" 2.8.6.数据源健康")]),e._v(" "),a("p",[a("code",[e._v("DataSource")]),e._v("健康指示器显示标准数据源和路由数据源 bean 的健康状况。路由数据源的健康状况包括其每个目标数据源的健康状况。在健康端点的响应中,每个路由数据源的目标都是通过使用其路由密钥来命名的。如果不希望在指示器的输出中包含路由数据源,请将"),a("code",[e._v("management.health.db.ignore-routing-data-sources")]),e._v("设置为"),a("code",[e._v("true")]),e._v("。")]),e._v(" "),a("h3",{attrs:{id:"_2-9-kubernetes-探测器"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-9-kubernetes-探测器"}},[e._v("#")]),e._v(" 2.9.Kubernetes 探测器")]),e._v(" "),a("p",[e._v("部署在 Kubernetes 上的应用程序可以用"),a("a",{attrs:{href:"https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes",target:"_blank",rel:"noopener noreferrer"}},[e._v("容器探针"),a("OutboundLink")],1),e._v("提供有关其内部状态的信息。根据"),a("a",{attrs:{href:"https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/",target:"_blank",rel:"noopener noreferrer"}},[e._v("你的 Kubernetes 配置"),a("OutboundLink")],1),e._v(",Kubelet 调用这些探测并对结果做出反应。")]),e._v(" "),a("p",[e._v("默认情况下, Spring boot 管理你的"),a("RouterLink",{attrs:{to:"/spring-boot/features.html#features.spring-application.application-availability"}},[e._v("应用程序可用性状态")]),e._v("。如果部署在 Kubernetes 环境中,致动器将从"),a("code",[e._v("ApplicationAvailability")]),e._v("接口收集“活性”和“就绪”信息,并在专用"),a("a",{attrs:{href:"#actuator.endpoints.health.auto-configured-health-indicators"}},[e._v("健康指标")]),e._v("中使用该信息:"),a("code",[e._v("LivenessStateHealthIndicator")]),e._v("和"),a("code",[e._v("ReadinessStateHealthIndicator")]),e._v("。这些指标显示在全球健康端点("),a("code",[e._v('"/actuator/health"')]),e._v(")上。通过使用"),a("a",{attrs:{href:"#actuator.endpoints.health.groups"}},[e._v("健康团体")]),e._v(":"),a("code",[e._v('"/actuator/health/liveness"')]),e._v("和"),a("code",[e._v('"/actuator/health/readiness"')]),e._v(",它们也可以作为单独的 HTTP 探针公开。")],1),e._v(" "),a("p",[e._v("然后,你可以使用以下端点信息来配置 Kubernetes 基础架构:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('livenessProbe:\n httpGet:\n path: "/actuator/health/liveness"\n port: \n failureThreshold: ...\n periodSeconds: ...\n\nreadinessProbe:\n httpGet:\n path: "/actuator/health/readiness"\n port: \n failureThreshold: ...\n periodSeconds: ...\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[a("code",[e._v("")]),e._v("应该设置为执行器端点可用的端口。"),a("br"),e._v("如果"),a("code",[e._v('"management.server.port"')]),e._v("属性已设置,则它可以是主 Web 服务器端口或单独的管理端口。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("只有当应用程序"),a("RouterLink",{attrs:{to:"/spring-boot/deployment.html#deployment.cloud.kubernetes"}},[e._v("在 Kubernetes 环境中运行")]),e._v("时,这些健康组才会自动启用。你可以通过使用"),a("code",[e._v("management.endpoint.health.probes.enabled")]),e._v("配置属性在任何环境中启用它们。")],1),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果一个应用程序的启动时间超过了配置的活动周期,Kubernetes 提到"),a("code",[e._v('"startupProbe"')]),e._v("是一个可能的解决方案。"),a("br"),e._v("这里不一定需要"),a("code",[e._v('"startupProbe"')]),e._v(",因为"),a("code",[e._v('"readinessProbe"')]),e._v("在完成所有启动任务之前都会失败。参见描述"),a("a",{attrs:{href:"#actuator.endpoints.kubernetes-probes.lifecycle"}},[e._v("探针在应用程序生命周期中的行为")]),e._v("的部分。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("如果你的执行器端点部署在单独的管理上下文中,那么端点不使用与主应用程序相同的 Web 基础设施(端口、连接池、框架组件)。在这种情况下,即使主应用程序不能正常工作(例如,它不能接受新的连接),探测检查也可能是成功的。出于这个原因,在主服务器端口上启用"),a("code",[e._v("liveness")]),e._v("和"),a("code",[e._v("readiness")]),e._v("健康组是一个好主意。这可以通过设置以下属性来完成:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoint.health.probes.add-additional-paths=true\n")])])]),a("p",[e._v("这将使"),a("code",[e._v("liveness")]),e._v("在主服务器端口上的"),a("code",[e._v("/livez")]),e._v("和"),a("code",[e._v("readiness")]),e._v("上可用。")]),e._v(" "),a("h4",{attrs:{id:"_2-9-1-用-kubernetes-探测器检查外部状态"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-9-1-用-kubernetes-探测器检查外部状态"}},[e._v("#")]),e._v(" 2.9.1.用 Kubernetes 探测器检查外部状态")]),e._v(" "),a("p",[e._v("Actuator 将“活性”和“准备”探测配置为健康小组。这意味着所有的"),a("a",{attrs:{href:"#actuator.endpoints.health.groups"}},[e._v("健康团体功能")]),e._v("对它们都是可用的。例如,你可以配置其他的健康指标:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoint.health.group.readiness.include=readinessState,customCheck\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoint:\n health:\n group:\n readiness:\n include: "readinessState,customCheck"\n')])])]),a("p",[e._v("默认情况下, Spring Boot 不会向这些组添加其他健康指标。")]),e._v(" "),a("p",[e._v("“活性”调查不应依赖于外部系统的健康检查。如果"),a("RouterLink",{attrs:{to:"/spring-boot/features.html#features.spring-application.application-availability.liveness"}},[e._v("应用程序的活性状态")]),e._v("被破坏,Kubernetes 将尝试通过重新启动应用程序实例来解决该问题。这意味着,如果外部系统(例如数据库、Web API 或外部缓存)发生故障,Kubernetes 可能会重新启动所有应用程序实例并产生级联故障。")],1),e._v(" "),a("p",[e._v("至于“就绪”调查,检查外部系统的选择必须由应用程序开发人员仔细做出。出于这个原因, Spring 引导不包括在准备状态探测中的任何额外的健康检查。如果"),a("RouterLink",{attrs:{to:"/spring-boot/features.html#features.spring-application.application-availability.readiness"}},[e._v("应用程序实例的准备状态")]),e._v("未准备好,Kubernetes 不会将通信量路由到该实例。一些外部系统可能不会被应用程序实例共享,在这种情况下,它们可能会被包含在就绪状态探测中。其他外部系统可能不是应用程序所必需的(应用程序可能有断路器和后备电源),在这种情况下,它们绝对不应该被包括在内。不幸的是,所有应用程序实例共享的外部系统是常见的,你必须做出判断:将其纳入准备状态调查,并期望当外部服务关闭或将其排除在外时,应用程序将退出服务,并处理堆栈中更高的故障,也许通过在呼叫者中使用断路器。")],1),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果应用程序的所有实例都没有准备好,那么带有"),a("code",[e._v("type=ClusterIP")]),e._v("或"),a("code",[e._v("NodePort")]),e._v("的 Kubernetes 服务不接受任何传入连接。"),a("br"),e._v("没有 HTTP 错误响应(503 等),因为没有连接。"),a("br"),e._v("带有"),a("code",[e._v("type=LoadBalancer")]),e._v("的服务可能接受连接,也可能不接受连接,取决于提供者。"),a("br"),e._v("具有显式"),a("a",{attrs:{href:"https://kubernetes.io/docs/concepts/services-networking/ingress/",target:"_blank",rel:"noopener noreferrer"}},[e._v("ingress"),a("OutboundLink")],1),e._v("的服务也以某种方式响应这取决于实现——Ingress 服务本身必须决定如何处理来自下游的“拒绝的连接”。"),a("br"),e._v("HTTP503 在负载均衡器和 Ingress 的情况下都很有可能发生。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("此外,如果一个应用程序使用 Kubernetes"),a("a",{attrs:{href:"https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/",target:"_blank",rel:"noopener noreferrer"}},[e._v("自动缩放"),a("OutboundLink")],1),e._v(",它可能会对从负载均衡器取出的应用程序做出不同的反应,这取决于它的自动定标器配置。")]),e._v(" "),a("h4",{attrs:{id:"_2-9-2-应用程序生命周期和探测状态"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-9-2-应用程序生命周期和探测状态"}},[e._v("#")]),e._v(" 2.9.2.应用程序生命周期和探测状态")]),e._v(" "),a("p",[e._v("Kubernetes Probes 支持的一个重要方面是它与应用程序生命周期的一致性。在"),a("code",[e._v("AvailabilityState")]),e._v("(这是应用程序在内存中的内部状态)和实际的探测(它公开了该状态)之间存在显著差异。根据应用程序生命周期的阶段,探测可能不可用。")]),e._v(" "),a("p",[e._v("Spring 引导发布"),a("RouterLink",{attrs:{to:"/spring-boot/features.html#features.spring-application.application-events-and-listeners"}},[e._v("启动和关闭过程中的应用程序事件")]),e._v(",并且探测可以侦听这样的事件并公开"),a("code",[e._v("AvailabilityState")]),e._v("信息。")],1),e._v(" "),a("p",[e._v("下表显示了"),a("code",[e._v("AvailabilityState")]),e._v("和 HTTP 连接器在不同阶段的状态。")]),e._v(" "),a("p",[e._v("当 Spring 启动应用程序启动时:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Startup phase")]),e._v(" "),a("th",[e._v("LivenessState")]),e._v(" "),a("th",[e._v("ReadinessState")]),e._v(" "),a("th",[e._v("HTTP server")]),e._v(" "),a("th",[e._v("笔记")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[e._v("Starting")]),e._v(" "),a("td",[a("code",[e._v("BROKEN")])]),e._v(" "),a("td",[a("code",[e._v("REFUSING_TRAFFIC")])]),e._v(" "),a("td",[e._v("Not started")]),e._v(" "),a("td",[e._v("Kubernetes 检查“活性”探测,如果时间太长,则重新启动应用程序。")])]),e._v(" "),a("tr",[a("td",[e._v("Started")]),e._v(" "),a("td",[a("code",[e._v("CORRECT")])]),e._v(" "),a("td",[a("code",[e._v("REFUSING_TRAFFIC")])]),e._v(" "),a("td",[e._v("Refuses requests")]),e._v(" "),a("td",[e._v("将刷新应用程序上下文。应用程序执行启动任务,但尚未接收到流量。")])]),e._v(" "),a("tr",[a("td",[e._v("Ready")]),e._v(" "),a("td",[a("code",[e._v("CORRECT")])]),e._v(" "),a("td",[a("code",[e._v("ACCEPTING_TRAFFIC")])]),e._v(" "),a("td",[e._v("Accepts requests")]),e._v(" "),a("td",[e._v("启动任务完成。应用程序正在接收流量。")])])])]),e._v(" "),a("p",[e._v("当 Spring 引导应用程序关闭时:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Shutdown phase")]),e._v(" "),a("th",[e._v("Liveness State")]),e._v(" "),a("th",[e._v("Readiness State")]),e._v(" "),a("th",[e._v("HTTP server")]),e._v(" "),a("th",[e._v("笔记")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[e._v("Running")]),e._v(" "),a("td",[a("code",[e._v("CORRECT")])]),e._v(" "),a("td",[a("code",[e._v("ACCEPTING_TRAFFIC")])]),e._v(" "),a("td",[e._v("Accepts requests")]),e._v(" "),a("td",[e._v("已请求关闭。")])]),e._v(" "),a("tr",[a("td",[e._v("Graceful shutdown")]),e._v(" "),a("td",[a("code",[e._v("CORRECT")])]),e._v(" "),a("td",[a("code",[e._v("REFUSING_TRAFFIC")])]),e._v(" "),a("td",[e._v("New requests are rejected")]),e._v(" "),a("td",[e._v("如果启用,"),a("RouterLink",{attrs:{to:"/spring-boot/web.html#web.graceful-shutdown"}},[e._v("优雅的关机处理飞行中的请求")]),e._v("。")],1)]),e._v(" "),a("tr",[a("td",[e._v("Shutdown complete")]),e._v(" "),a("td",[e._v("N/A")]),e._v(" "),a("td",[e._v("N/A")]),e._v(" "),a("td",[e._v("Server is shut down")]),e._v(" "),a("td",[e._v("应用程序上下文是关闭的,应用程序是关闭的。")])])])]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("有关 Kubernetes 部署的更多信息,请参见"),a("RouterLink",{attrs:{to:"/spring-boot/deployment.html#deployment.cloud.kubernetes.container-lifecycle"}},[e._v("Kubernetes 容器生命周期部分")]),e._v("。")],1)])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"_2-10-应用程序信息"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-应用程序信息"}},[e._v("#")]),e._v(" 2.10.应用程序信息")]),e._v(" "),a("p",[e._v("应用程序信息公开了从所有["),a("code",[e._v("InfoContributor")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/org/org/springframework/boot/actuate/actuate/info/infrocontributor.java)bean 中收集的各种信息,这些 bean 定义在你的.enabled")]),e._v("属性控制。不同的贡献者对此属性有不同的默认值,这取决于他们的先决条件和他们公开的信息的性质。")]),e._v(" "),a("p",[e._v("由于没有先决条件表明应该启用它们,"),a("code",[e._v("env")]),e._v("和"),a("code",[e._v("java")]),e._v("贡献者默认情况下是禁用的。你可以通过将"),a("code",[e._v("management.info.env.enabled")]),e._v("或"),a("code",[e._v("management.info.java.enabled")]),e._v("属性设置为"),a("code",[e._v("true")]),e._v("来启用它们。")]),e._v(" "),a("p",[e._v("默认情况下启用"),a("code",[e._v("build")]),e._v("和"),a("code",[e._v("git")]),e._v("信息贡献者。可以通过将其"),a("code",[e._v("management.info..enabled")]),e._v("属性设置为"),a("code",[e._v("false")]),e._v("来禁用每个属性。或者,要禁用每个默认情况下通常启用的贡献者,请将"),a("code",[e._v("management.info.defaults.enabled")]),e._v("属性设置为"),a("code",[e._v("false")]),e._v("。")]),e._v(" "),a("h4",{attrs:{id:"_2-10-2-自定义应用程序信息"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-2-自定义应用程序信息"}},[e._v("#")]),e._v(" 2.10.2.自定义应用程序信息")]),e._v(" "),a("p",[e._v("当"),a("code",[e._v("env")]),e._v("contributor 被启用时,你可以通过设置"),a("code",[e._v("info.*")]),e._v(" Spring 属性来定制由"),a("code",[e._v("info")]),e._v("端点公开的数据。在"),a("code",[e._v("info")]),e._v("键下的所有"),a("code",[e._v("Environment")]),e._v("属性都会自动公开。例如,你可以在"),a("code",[e._v("application.properties")]),e._v("文件中添加以下设置:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("info.app.encoding=UTF-8\ninfo.app.java.source=11\ninfo.app.java.target=11\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('info:\n app:\n encoding: "UTF-8"\n java:\n source: "11"\n target: "11"\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("而不是硬编码这些值,你也可以"),a("RouterLink",{attrs:{to:"/spring-boot/howto.html#howto.properties-and-configuration.expand-properties"}},[e._v("在构建时展开信息属性")]),e._v("。"),a("br"),a("br"),e._v("假设你使用 Maven,你可以将前面的示例重写如下:"),a("br"),a("br"),e._v("属性"),a("br"),a("br"),a("br"),e._v('593<582">>>')],1)])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_2-10-3-git-提交信息"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-3-git-提交信息"}},[e._v("#")]),e._v(" 2.10.3.Git 提交信息")]),e._v(" "),a("p",[a("code",[e._v("info")]),e._v("端点的另一个有用特性是,它能够在构建项目时发布有关你的"),a("code",[e._v("git")]),e._v("源代码库状态的信息。如果"),a("code",[e._v("Git属性")]),e._v(" Bean 是可用的,则可以使用"),a("code",[e._v("info")]),e._v("端点来公开这些属性。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果"),a("code",[e._v("git.properties")]),e._v("文件在 Classpath 的根目录下可用,则"),a("code",[e._v("Git属性")]),e._v(" Bean 是自动配置的。"),a("br"),e._v("有关更多详细信息,请参见“"),a("RouterLink",{attrs:{to:"/spring-boot/howto.html#howto.build.generate-git-info"}},[e._v("如何生成 Git 信息")]),e._v("”。")],1)])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("默认情况下,端点公开"),a("code",[e._v("git.branch")]),e._v("、"),a("code",[e._v("git.commit.id")]),e._v("和"),a("code",[e._v("git.commit.time")]),e._v("属性(如果存在的话)。如果不希望在端点响应中包含任何这些属性,则需要将它们从"),a("code",[e._v("git.properties")]),e._v("文件中排除。如果要显示完整的 Git 信息(即"),a("code",[e._v("git.properties")]),e._v("的完整内容),请使用"),a("code",[e._v("management.info.git.mode")]),e._v("属性,如下所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.info.git.mode=full\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n info:\n git:\n mode: "full"\n')])])]),a("p",[e._v("要完全禁用来自"),a("code",[e._v("info")]),e._v("端点的 Git 提交信息,请将"),a("code",[e._v("management.info.git.enabled")]),e._v("属性设置为"),a("code",[e._v("false")]),e._v(",如下所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.info.git.enabled=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n info:\n git:\n enabled: false\n")])])]),a("h4",{attrs:{id:"_2-10-4-建立信息"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-4-建立信息"}},[e._v("#")]),e._v(" 2.10.4.建立信息")]),e._v(" "),a("p",[e._v("如果"),a("code",[e._v("Build属性")]),e._v(" Bean 是可用的,那么"),a("code",[e._v("info")]),e._v("端点也可以发布有关你的构建的信息。如果"),a("code",[e._v("META-INF/build-info.properties")]),e._v("文件在 Classpath 中可用,就会发生这种情况。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("Maven 和 Gradle 插件都可以生成该文件。"),a("br"),e._v("有关更多详细信息,请参见“"),a("RouterLink",{attrs:{to:"/spring-boot/howto.html#howto.build.generate-info"}},[e._v("如何生成构建信息")]),e._v("”。")],1)])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_2-10-5-java-信息"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-5-java-信息"}},[e._v("#")]),e._v(" 2.10.5.Java 信息")]),e._v(" "),a("p",[a("code",[e._v("info")]),e._v("端点发布有关你的 Java 运行时环境的信息,有关更多详细信息,请参见["),a("code",[e._v("JavaInfo")]),e._v("](https://DOCS. Spring.io/ Spring-boot/DOCS/2.6.4/api/org/springframework/boot/info/info/javainfo.html)。")]),e._v(" "),a("h4",{attrs:{id:"_2-10-6-编写自定义信息贡献者"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-6-编写自定义信息贡献者"}},[e._v("#")]),e._v(" 2.10.6.编写自定义信息贡献者")]),e._v(" "),a("p",[e._v("要提供自定义的应用程序信息,你可以注册实现["),a("code",[e._v("InfoContributor")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-actuator/SRC/main/java/org/springframework/boot/actuate/actuate/info/info/infutor.java)接口的 Spring bean。")]),e._v(" "),a("p",[e._v("下面的示例以单个值贡献一个"),a("code",[e._v("example")]),e._v("条目:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('import java.util.Collections;\n\nimport org.springframework.boot.actuate.info.Info;\nimport org.springframework.boot.actuate.info.InfoContributor;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyInfoContributor implements InfoContributor {\n\n @Override\n public void contribute(Info.Builder builder) {\n builder.withDetail("example", Collections.singletonMap("key", "value"));\n }\n\n}\n\n')])])]),a("p",[e._v("如果你到达"),a("code",[e._v("info")]),e._v("端点,你应该会看到一个包含以下附加条目的响应:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('{\n "example": {\n "key" : "value"\n }\n}\n')])])]),a("h2",{attrs:{id:"_3-基于-http-的监控和管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-基于-http-的监控和管理"}},[e._v("#")]),e._v(" 3. 基于 HTTP 的监控和管理")]),e._v(" "),a("p",[e._v("如果你正在开发一个 Web 应用程序, Spring Boot Actuator 自动配置所有启用的端点,以便通过 HTTP 公开。默认的约定是使用前缀"),a("code",[e._v("/actuator")]),e._v("的端点的"),a("code",[e._v("id")]),e._v("作为 URL 路径。例如,"),a("code",[e._v("health")]),e._v("被暴露为"),a("code",[e._v("/actuator/health")]),e._v("。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("Spring MVC、 Spring WebFlux 和 Jersey 原生地支持致动器。如果 Jersey 和 Spring MVC 都可用,则使用 Spring MVC。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("Jackson 是一个必需的依赖项,以便获得 API 文档中记录的正确的 JSON 响应("),a("a",{attrs:{href:"https://docs.spring.io/spring-boot/docs/2.6.4/actuator-api/htmlsingle",target:"_blank",rel:"noopener noreferrer"}},[e._v("HTML"),a("OutboundLink")],1),e._v("或"),a("a",{attrs:{href:"https://docs.spring.io/spring-boot/docs/2.6.4/actuator-api/pdf/spring-boot-actuator-web-api.pdf",target:"_blank",rel:"noopener noreferrer"}},[e._v("PDF"),a("OutboundLink")],1),e._v(")。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"_3-1-自定义管理端点路径"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-1-自定义管理端点路径"}},[e._v("#")]),e._v(" 3.1.自定义管理端点路径")]),e._v(" "),a("p",[e._v("有时,定制管理端点的前缀是有用的。例如,你的应用程序可能已经将"),a("code",[e._v("/actuator")]),e._v("用于其他目的。可以使用"),a("code",[e._v("management.endpoints.web.base-path")]),e._v("属性更改管理端点的前缀,如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.web.base-path=/manage\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoints:\n web:\n base-path: "/manage"\n')])])]),a("p",[e._v("前面的"),a("code",[e._v("application.properties")]),e._v("示例将端点从"),a("code",[e._v("/actuator/{id}")]),e._v("更改为"),a("code",[e._v("/manage/{id}")]),e._v("(例如,"),a("code",[e._v("/manage/info")]),e._v(")。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("除非管理端口已被配置为"),a("a",{attrs:{href:"#actuator.monitoring.customizing-management-server-port"}},[e._v("使用不同的 HTTP 端口公开端点")]),e._v(",否则"),a("code",[e._v("management.endpoints.web.base-path")]),e._v("相对于"),a("code",[e._v("server.servlet.context-path")]),e._v("(对于 Servlet Web 应用程序)或"),a("code",[e._v("spring.webflux.base-path")]),e._v("(对于反应性 Web 应用程序)。"),a("br"),e._v("如果配置了"),a("code",[e._v("management.server.port")]),e._v(",则"),a("code",[e._v("management.endpoints.web.base-path")]),e._v("相对于"),a("code",[e._v("management.server.base-path")]),e._v("。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("如果希望将端点映射到不同的路径,可以使用"),a("code",[e._v("management.endpoints.web.path-mapping")]),e._v("属性。")]),e._v(" "),a("p",[e._v("下面的示例将"),a("code",[e._v("/actuator/health")]),e._v("重新映射到"),a("code",[e._v("/healthcheck")]),e._v(":")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.web.base-path=/\nmanagement.endpoints.web.path-mapping.health=healthcheck\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoints:\n web:\n base-path: "/"\n path-mapping:\n health: "healthcheck"\n')])])]),a("h3",{attrs:{id:"_3-2-自定义管理服务器端口"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-2-自定义管理服务器端口"}},[e._v("#")]),e._v(" 3.2.自定义管理服务器端口")]),e._v(" "),a("p",[e._v("对于基于云的部署,使用默认的 HTTP 端口公开管理端点是一个明智的选择。但是,如果你的应用程序在你自己的数据中心内运行,那么你可能更喜欢使用不同的 HTTP 端口来公开端点。")]),e._v(" "),a("p",[e._v("你可以设置"),a("code",[e._v("management.server.port")]),e._v("属性来更改 HTTP 端口,如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.server.port=8081\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n server:\n port: 8081\n")])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("在 Cloud Foundry 上,默认情况下,应用程序仅在端口 8080 上接收用于 HTTP 和 TCP 路由的请求。"),a("br"),e._v("如果你想在 Cloud Foundry 上使用自定义管理端口,则需要显式地设置应用程序的路由以将流量转发到自定义端口。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"_3-3-配置特定于管理的-ssl"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-3-配置特定于管理的-ssl"}},[e._v("#")]),e._v(" 3.3.配置特定于管理的 SSL")]),e._v(" "),a("p",[e._v("当配置为使用自定义端口时,你还可以通过使用各种"),a("code",[e._v("management.server.ssl.*")]),e._v("属性,将管理服务器配置为它自己的 SSL。例如,这样做可以让管理服务器在 HTTP 上可用,而主应用程序使用 HTTPS,如下列属性设置所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("server.port=8443\nserver.ssl.enabled=true\nserver.ssl.key-store=classpath:store.jks\nserver.ssl.key-password=secret\nmanagement.server.port=8080\nmanagement.server.ssl.enabled=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('server:\n port: 8443\n ssl:\n enabled: true\n key-store: "classpath:store.jks"\n key-password: "secret"\nmanagement:\n server:\n port: 8080\n ssl:\n enabled: false\n')])])]),a("p",[e._v("或者,主服务器和管理服务器都可以使用 SSL,但使用不同的密钥存储,如下所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("server.port=8443\nserver.ssl.enabled=true\nserver.ssl.key-store=classpath:main.jks\nserver.ssl.key-password=secret\nmanagement.server.port=8080\nmanagement.server.ssl.enabled=true\nmanagement.server.ssl.key-store=classpath:management.jks\nmanagement.server.ssl.key-password=secret\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('server:\n port: 8443\n ssl:\n enabled: true\n key-store: "classpath:main.jks"\n key-password: "secret"\nmanagement:\n server:\n port: 8080\n ssl:\n enabled: true\n key-store: "classpath:management.jks"\n key-password: "secret"\n')])])]),a("h3",{attrs:{id:"_3-4-自定义管理服务器地址"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-4-自定义管理服务器地址"}},[e._v("#")]),e._v(" 3.4.自定义管理服务器地址")]),e._v(" "),a("p",[e._v("你可以通过设置"),a("code",[e._v("management.server.address")]),e._v("属性来定制管理端点可用的地址。如果你只想监听内部或面向 Ops 的网络,或者只监听"),a("code",[e._v("localhost")]),e._v("中的连接,那么这样做会很有用。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("只有当端口与主服务器端口不同时,你才可以在不同的地址上监听。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("以下示例"),a("code",[e._v("application.properties")]),e._v("不允许远程管理连接:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.server.port=8081\nmanagement.server.address=127.0.0.1\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n server:\n port: 8081\n address: "127.0.0.1"\n')])])]),a("h3",{attrs:{id:"_3-5-禁用-http-端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-5-禁用-http-端点"}},[e._v("#")]),e._v(" 3.5.禁用 HTTP 端点")]),e._v(" "),a("p",[e._v("如果不想在 HTTP 上公开端点,可以将管理端口设置为"),a("code",[e._v("-1")]),e._v(",如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.server.port=-1\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n server:\n port: -1\n")])])]),a("p",[e._v("你也可以通过使用"),a("code",[e._v("management.endpoints.web.exposure.exclude")]),e._v("属性来实现这一点,如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.web.exposure.exclude=*\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoints:\n web:\n exposure:\n exclude: "*"\n')])])]),a("h2",{attrs:{id:"_4-jmx-的监控与管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-jmx-的监控与管理"}},[e._v("#")]),e._v(" 4. JMX 的监控与管理")]),e._v(" "),a("p",[e._v("Java 管理扩展提供了一种标准的机制来监视和管理应用程序。默认情况下,不启用此功能。你可以通过将"),a("code",[e._v("spring.jmx.enabled")]),e._v("配置属性设置为"),a("code",[e._v("true")]),e._v("来打开它。 Spring 引导将最合适的"),a("code",[e._v("MBeanServer")]),e._v("公开为具有"),a("code",[e._v("mbeanServer")]),e._v("的 ID 的 Bean。使用 Spring JMX 注释("),a("code",[e._v("@ManagedResource")]),e._v(","),a("code",[e._v("@ManagedAttribute")]),e._v(",或"),a("code",[e._v("@ManagedOperation")]),e._v(")进行注释的任何 bean 都会暴露给它。")]),e._v(" "),a("p",[e._v("如果你的平台提供了一个标准的"),a("code",[e._v("MBeanServer")]),e._v(", Spring boot 将使用它,并在必要时默认为 VM"),a("code",[e._v("MBeanServer")]),e._v("。如果所有这些都失败了,将创建一个新的"),a("code",[e._v("MBeanServer")]),e._v("。")]),e._v(" "),a("p",[e._v("参见["),a("code",[e._v("JmxAutoConfiguration")]),e._v("](https://github.com/ Spring-projects/ Spring-boot/tree/v2.6.4/ Spring-boot-project/ Spring-boot-autofigure/SRC/main/java/org/springframework/boot/autofigure/jmx/jmxautofconfiguration.java)类获取更多详细信息。")]),e._v(" "),a("p",[e._v("默认情况下, Spring 引导还将管理端点作为"),a("code",[e._v("org.springframework.boot")]),e._v("域下的 JMXMBeans 公开。要完全控制 JMX 域中的端点注册,请考虑注册你自己的"),a("code",[e._v("EndpointObjectNameFactory")]),e._v("实现。")]),e._v(" "),a("h3",{attrs:{id:"_4-1-自定义-mbean-名称"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-1-自定义-mbean-名称"}},[e._v("#")]),e._v(" 4.1.自定义 MBean 名称")]),e._v(" "),a("p",[e._v("MBean 的名称通常是从端点的"),a("code",[e._v("id")]),e._v("生成的。例如,将"),a("code",[e._v("health")]),e._v("端点暴露为"),a("code",[e._v("org.springframework.boot:type=Endpoint,name=Health")]),e._v("。")]),e._v(" "),a("p",[e._v("如果你的应用程序包含多个 Spring "),a("code",[e._v("ApplicationContext")]),e._v(",则可能会发现名称冲突。要解决此问题,可以将"),a("code",[e._v("spring.jmx.unique-names")]),e._v("属性设置为"),a("code",[e._v("true")]),e._v(",这样 MBean 名称就始终是唯一的。")]),e._v(" "),a("p",[e._v("你还可以自定义公开端点的 JMX 域。以下设置在"),a("code",[e._v("application.properties")]),e._v("中显示了这样做的示例:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("spring.jmx.unique-names=true\nmanagement.endpoints.jmx.domain=com.example.myapp\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('spring:\n jmx:\n unique-names: true\nmanagement:\n endpoints:\n jmx:\n domain: "com.example.myapp"\n')])])]),a("h3",{attrs:{id:"_4-2-禁用-jmx-端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-2-禁用-jmx-端点"}},[e._v("#")]),e._v(" 4.2.禁用 JMX 端点")]),e._v(" "),a("p",[e._v("如果不想在 JMX 上公开端点,可以将"),a("code",[e._v("management.endpoints.jmx.exposure.exclude")]),e._v("属性设置为"),a("code",[e._v("*")]),e._v(",如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoints.jmx.exposure.exclude=*\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n endpoints:\n jmx:\n exposure:\n exclude: "*"\n')])])]),a("h3",{attrs:{id:"_4-3-在-http-上使用-jolokia-进行-jmx"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-3-在-http-上使用-jolokia-进行-jmx"}},[e._v("#")]),e._v(" 4.3.在 HTTP 上使用 Jolokia 进行 JMX")]),e._v(" "),a("p",[e._v("Jolokia 是一个 JMX-HTTP 桥,它提供了一种访问 JMX Bean 的替代方法。若要使用 Jolokia,请包含对"),a("code",[e._v("org.jolokia:jolokia-core")]),e._v("的依赖关系。例如,对于 Maven,你将添加以下依赖项:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("\n org.jolokia\n jolokia-core\n\n")])])]),a("p",[e._v("然后,你可以通过向"),a("code",[e._v("management.endpoints.web.exposure.include")]),e._v("属性添加"),a("code",[e._v("jolokia")]),e._v("或"),a("code",[e._v("*")]),e._v("来公开 Jolokia 端点。然后,你可以使用管理 HTTP 服务器上的"),a("code",[e._v("/actuator/jolokia")]),e._v("访问它。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("Jolokia 端点将 Jolokia 的 Servlet 公开为执行器端点。"),a("br"),e._v("结果,它是特定于 Servlet 环境的,例如 Spring MVC 和 Jersey。"),a("br"),e._v("端点在 WebFlux 应用程序中是不可用的。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_4-3-1-定制-jolokia"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-3-1-定制-jolokia"}},[e._v("#")]),e._v(" 4.3.1.定制 Jolokia")]),e._v(" "),a("p",[e._v("Jolokia 有许多设置,你通常会通过设置 Servlet 参数来配置这些设置。通过 Spring 引导,你可以使用你的"),a("code",[e._v("application.properties")]),e._v("文件。要这样做,请在参数前缀"),a("code",[e._v("management.endpoint.jolokia.config.")]),e._v(",如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoint.jolokia.config.debug=true\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n endpoint:\n jolokia:\n config:\n debug: true\n")])])]),a("h4",{attrs:{id:"_4-3-2-禁用-jolokia"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-3-2-禁用-jolokia"}},[e._v("#")]),e._v(" 4.3.2.禁用 Jolokia")]),e._v(" "),a("p",[e._v("如果你使用 Jolokia,但不希望 Spring 引导来配置它,请将"),a("code",[e._v("management.endpoint.jolokia.enabled")]),e._v("属性设置为"),a("code",[e._v("false")]),e._v(",如下所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.endpoint.jolokia.enabled=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n endpoint:\n jolokia:\n enabled: false\n")])])]),a("h2",{attrs:{id:"_5-日志记录器"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_5-日志记录器"}},[e._v("#")]),e._v(" 5. 日志记录器")]),e._v(" "),a("p",[e._v("Spring 启动执行器包括在运行时查看和配置应用程序的日志级别的能力。你可以查看整个列表,也可以查看单个日志程序的配置,该配置由显式配置的日志级别以及日志框架赋予它的有效日志级别组成。这些级别可以是:")]),e._v(" "),a("ul",[a("li",[a("p",[a("code",[e._v("TRACE")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("DEBUG")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("INFO")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("WARN")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("ERROR")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("FATAL")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("OFF")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("null")])])])]),e._v(" "),a("p",[a("code",[e._v("null")]),e._v("表示没有显式配置。")]),e._v(" "),a("h3",{attrs:{id:"_5-1-配置记录器"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-配置记录器"}},[e._v("#")]),e._v(" 5.1.配置记录器")]),e._v(" "),a("p",[e._v("要配置给定的记录器,"),a("code",[e._v("POST")]),e._v("将一个部分实体配置到资源的 URI,如下例所示:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('{\n "configuredLevel": "DEBUG"\n}\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("要“重置”记录器的特定级别(并使用默认配置),可以将值"),a("code",[e._v("null")]),e._v("传递为"),a("code",[e._v("configuredLevel")]),e._v("。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h2",{attrs:{id:"_6-度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-度量"}},[e._v("#")]),e._v(" 6. 度量")]),e._v(" "),a("p",[e._v("Spring Boot Actuator 为"),a("a",{attrs:{href:"https://micrometer.io",target:"_blank",rel:"noopener noreferrer"}},[e._v("Micrometer"),a("OutboundLink")],1),e._v("提供依赖管理和自动配置,这是一种支持"),a("a",{attrs:{href:"https://micrometer.io/docs",target:"_blank",rel:"noopener noreferrer"}},[e._v("众多的监测系统"),a("OutboundLink")],1),e._v("的应用程序度量外观,包括:")]),e._v(" "),a("ul",[a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.appoptics"}},[e._v("AppOptics")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.atlas"}},[e._v("Atlas")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.datadog"}},[e._v("Datadog")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.dynatrace"}},[e._v("Dynatrace")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.elastic"}},[e._v("Elastic")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.ganglia"}},[e._v("Ganglia")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.graphite"}},[e._v("Graphite")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.humio"}},[e._v("Humio")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.influx"}},[e._v("Influx")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.jmx"}},[e._v("JMX")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.kairos"}},[e._v("KairosDB")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.newrelic"}},[e._v("New Relic")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.prometheus"}},[e._v("Prometheus")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.signalfx"}},[e._v("SignalFx")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.simple"}},[e._v("简单(内存中)")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.stackdriver"}},[e._v("Stackdriver")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.statsd"}},[e._v("StatsD")])])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"#actuator.metrics.export.wavefront"}},[e._v("Wavefront")])])])]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("要了解有关千分尺功能的更多信息,请参见其"),a("a",{attrs:{href:"https://micrometer.io/docs",target:"_blank",rel:"noopener noreferrer"}},[e._v("参考文献"),a("OutboundLink")],1),e._v(",特别是"),a("a",{attrs:{href:"https://micrometer.io/docs/concepts",target:"_blank",rel:"noopener noreferrer"}},[e._v("概念部分"),a("OutboundLink")],1),e._v("。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"_6-1-开始"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-1-开始"}},[e._v("#")]),e._v(" 6.1.开始")]),e._v(" "),a("p",[e._v("Spring 引导自动配置组合"),a("code",[e._v("MeterRegistry")]),e._v(",并为其在 Classpath 上找到的每个支持的实现向组合添加注册表。在运行时 Classpath 中对"),a("code",[e._v("micrometer-registry-{system}")]),e._v("具有依赖关系就足以使 Spring 引导配置注册表。")]),e._v(" "),a("p",[e._v("大多数注册中心都有共同的特征。例如,即使在 Classpath 上的微米表注册实现也可以禁用特定的注册中心。以下示例禁用 Datadog:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.datadog.enabled=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n metrics:\n export:\n datadog:\n enabled: false\n")])])]),a("p",[e._v("除非特定于注册中心的属性另有说明,否则你也可以禁用所有注册中心,如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.defaults.enabled=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n metrics:\n export:\n defaults:\n enabled: false\n")])])]),a("p",[e._v("Spring Boot 还将任何自动配置的注册中心添加到"),a("code",[e._v("Metrics")]),e._v("类上的全局静态复合注册中心,除非你明确地告诉它不要:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.use-global-registry=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n metrics:\n use-global-registry: false\n")])])]),a("p",[e._v("你可以注册任意数量的"),a("code",[e._v("MeterRegistryCustomizer")]),e._v("bean,以进一步配置注册表,例如在向注册表注册任何米之前应用公共标记:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('import io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyMeterRegistryConfiguration {\n\n @Bean\n public MeterRegistryCustomizer metricsCommonTags() {\n return (registry) -> registry.config().commonTags("region", "us-east-1");\n }\n\n}\n\n')])])]),a("p",[e._v("你可以通过更具体地说明泛型类型来对特定的注册中心实现应用自定义:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("import io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.config.NamingConvention;\nimport io.micrometer.graphite.GraphiteMeterRegistry;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyMeterRegistryConfiguration {\n\n @Bean\n public MeterRegistryCustomizer graphiteMetricsNamingConvention() {\n return (registry) -> registry.config().namingConvention(this::name);\n }\n\n private String name(String name, Meter.Type type, String baseUnit) {\n return ...\n }\n\n}\n\n")])])]),a("p",[e._v("Spring 还可以启动"),a("a",{attrs:{href:"#actuator.metrics.supported"}},[e._v("配置内置的仪表")]),e._v(",这可以通过配置或专用注释标记来控制。")]),e._v(" "),a("h3",{attrs:{id:"_6-2-支持的监测系统"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-支持的监测系统"}},[e._v("#")]),e._v(" 6.2.支持的监测系统")]),e._v(" "),a("p",[e._v("这一节简要介绍了每个支持的监控系统。")]),e._v(" "),a("h4",{attrs:{id:"_6-2-1-appatics"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-1-appatics"}},[e._v("#")]),e._v(" 6.2.1.APPATICS")]),e._v(" "),a("p",[e._v("默认情况下,AppOptics 注册中心会定期将指标推到"),a("code",[e._v("[api.appoptics.com/v1/measurements](https://api.appoptics.com/v1/measurements)")]),e._v("。要将度量导出到 SaaS"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/appOptics",target:"_blank",rel:"noopener noreferrer"}},[e._v("AppOptics"),a("OutboundLink")],1),e._v(",必须提供你的 API 令牌:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.appoptics.api-token=YOUR_TOKEN\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n appoptics:\n api-token: "YOUR_TOKEN"\n')])])]),a("h4",{attrs:{id:"_6-2-2-阿特拉斯"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-2-阿特拉斯"}},[e._v("#")]),e._v(" 6.2.2.阿特拉斯")]),e._v(" "),a("p",[e._v("默认情况下,指标导出到在本地机器上运行的"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/atlas",target:"_blank",rel:"noopener noreferrer"}},[e._v("Atlas"),a("OutboundLink")],1),e._v("。你可以提供"),a("a",{attrs:{href:"https://github.com/Netflix/atlas",target:"_blank",rel:"noopener noreferrer"}},[e._v("Atlas 服务器"),a("OutboundLink")],1),e._v("的位置:")]),e._v(" "),a("p",[e._v("Properties")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.atlas.uri=https://atlas.example.com:7101/api/v1/publish\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n atlas:\n uri: "https://atlas.example.com:7101/api/v1/publish"\n')])])]),a("h4",{attrs:{id:"_6-2-3-datadog"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-3-datadog"}},[e._v("#")]),e._v(" 6.2.3.Datadog")]),e._v(" "),a("p",[e._v("Datadog 注册中心定期将指标推到"),a("a",{attrs:{href:"https://www.datadoghq.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("datadoghq"),a("OutboundLink")],1),e._v("。要将指标导出到"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/datadog",target:"_blank",rel:"noopener noreferrer"}},[e._v("Datadog"),a("OutboundLink")],1),e._v(",你必须提供你的 API 键:")]),e._v(" "),a("p",[e._v("Properties")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.datadog.api-key=YOUR_KEY\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n datadog:\n api-key: "YOUR_KEY"\n')])])]),a("p",[e._v("你还可以更改将指标发送到 Datadog 的时间间隔:")]),e._v(" "),a("p",[e._v("Properties")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.datadog.step=30s\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n datadog:\n step: "30s"\n')])])]),a("h4",{attrs:{id:"_6-2-4-dynatrace"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-4-dynatrace"}},[e._v("#")]),e._v(" 6.2.4.Dynatrace")]),e._v(" "),a("p",[e._v("Dynatrace 提供了两个吸收 API 的指标,这两个指标都是为"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/dynatrace",target:"_blank",rel:"noopener noreferrer"}},[e._v("Micrometer"),a("OutboundLink")],1),e._v("实现的。"),a("code",[e._v("v1")]),e._v("命名空间中的配置属性仅在导出到"),a("a",{attrs:{href:"https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v1/",target:"_blank",rel:"noopener noreferrer"}},[e._v("TimeSeries V1API"),a("OutboundLink")],1),e._v("时才应用。"),a("code",[e._v("v2")]),e._v("名称空间中的配置属性仅在导出到"),a("a",{attrs:{href:"https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v2/post-ingest-metrics/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Metrics V2API"),a("OutboundLink")],1),e._v("时才应用。注意,这种集成一次只能导出到 API 的"),a("code",[e._v("v1")]),e._v("或"),a("code",[e._v("v2")]),e._v("版本。如果"),a("code",[e._v("device-id")]),e._v("(v1 需要,但在 v2 中不使用)在"),a("code",[e._v("v1")]),e._v("命名空间中设置,则将指标导出到"),a("code",[e._v("v1")]),e._v("端点。否则,假定"),a("code",[e._v("v2")]),e._v("。")]),e._v(" "),a("h5",{attrs:{id:"v2api"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#v2api"}},[e._v("#")]),e._v(" V2API")]),e._v(" "),a("p",[e._v("你可以通过两种方式使用 V2API。")]),e._v(" "),a("p",[e._v("如果本地 OneAgent 在主机上运行,则度量指标将自动导出到"),a("a",{attrs:{href:"https://www.dynatrace.com/support/help/how-to-use-dynatrace/metrics/metric-ingestion/ingestion-methods/local-api/",target:"_blank",rel:"noopener noreferrer"}},[e._v("本地一个代理摄取端点"),a("OutboundLink")],1),e._v("。摄取端点将指标转发到 Dynatrace 后端。这是默认的行为,除了依赖于"),a("code",[e._v("io.micrometer:micrometer-registry-dynatrace")]),e._v("之外,不需要特殊的设置。")]),e._v(" "),a("p",[e._v("如果没有运行本地 OneAgent,则需要"),a("a",{attrs:{href:"https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v2/post-ingest-metrics/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Metrics V2API"),a("OutboundLink")],1),e._v("的端点和一个 API 令牌。"),a("a",{attrs:{href:"https://www.dynatrace.com/support/help/dynatrace-api/basics/dynatrace-api-authentication/",target:"_blank",rel:"noopener noreferrer"}},[e._v("API token"),a("OutboundLink")],1),e._v("必须具有“摄入指标”("),a("code",[e._v("metrics.ingest")]),e._v(")权限集。我们建议将令牌的范围限制为这个权限。你必须确保端点 URI 包含以下路径(例如,"),a("code",[e._v("/api/v2/metrics/ingest")]),e._v("):")]),e._v(" "),a("p",[e._v("根据你的部署选项,Metrics API v2Ingest 端点的 URL 是不同的:")]),e._v(" "),a("ul",[a("li",[a("p",[e._v("SaaS:"),a("code",[e._v("https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest")])])]),e._v(" "),a("li",[a("p",[e._v("托管部署:"),a("code",[e._v("https://{your-domain}/e/{your-environment-id}/api/v2/metrics/ingest")])])])]),e._v(" "),a("p",[e._v("下面的示例使用"),a("code",[e._v("example")]),e._v("环境 ID 配置指标导出:")]),e._v(" "),a("p",[e._v("Properties")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.dynatrace.uri=https://example.live.dynatrace.com/api/v2/metrics/ingest\nmanagement.metrics.export.dynatrace.api-token=YOUR_TOKEN\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n dynatrace:\n uri: "https://example.live.dynatrace.com/api/v2/metrics/ingest"\n api-token: "YOUR_TOKEN"\n')])])]),a("p",[e._v("在使用 Dynatrace V2API 时,可以使用以下可选特性:")]),e._v(" "),a("ul",[a("li",[a("p",[e._v("公制密钥前缀:设置一个前缀,该前缀用于所有导出的公制密钥。")])]),e._v(" "),a("li",[a("p",[e._v("丰富 Dynatrace 元数据:如果正在运行一个 Agent 或 Dynatrace 操作符,则使用额外的元数据(例如,关于主机、进程或 POD)丰富度量。")])]),e._v(" "),a("li",[a("p",[e._v("默认维度:指定添加到所有导出度量中的键-值对。如果使用 Micrometer 指定了具有相同键值的标记,则它们会覆盖默认的尺寸。")])])]),e._v(" "),a("p",[e._v("可以不指定 URI 和 API 令牌,如下面的示例所示。在此场景中,使用本地 OneAgent 端点:")]),e._v(" "),a("p",[e._v("Properties")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.dynatrace.v2.metric-key-prefix=your.key.prefix\nmanagement.metrics.export.dynatrace.v2.enrich-with-dynatrace-metadata=true\nmanagement.metrics.export.dynatrace.v2.default-dimensions.key1=value1\nmanagement.metrics.export.dynatrace.v2.default-dimensions.key2=value2\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n dynatrace:\n # Specify uri and api-token here if not using the local OneAgent endpoint.\n v2:\n metric-key-prefix: "your.key.prefix"\n enrich-with-dynatrace-metadata: true\n default-dimensions:\n key1: "value1"\n key2: "value2"\n')])])]),a("h5",{attrs:{id:"v1api-旧版"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#v1api-旧版"}},[e._v("#")]),e._v(" V1API(旧版)")]),e._v(" "),a("p",[e._v("Dynatrace V1API metrics 注册中心通过使用"),a("a",{attrs:{href:"https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v1/",target:"_blank",rel:"noopener noreferrer"}},[e._v("TimeSeries V1API"),a("OutboundLink")],1),e._v("定期将指标推送到配置的 URI。对于与现有设置的向后兼容性,当设置"),a("code",[e._v("device-id")]),e._v("时(对于 V1 是必需的,但在 V2 中不使用),度量值将导出到 TimeSeries V1 端点。要将指标导出到"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/dynatrace",target:"_blank",rel:"noopener noreferrer"}},[e._v("Dynatrace"),a("OutboundLink")],1),e._v(",必须提供你的 API 令牌、设备 ID 和 URI:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.dynatrace.uri=https://{your-environment-id}.live.dynatrace.com\nmanagement.metrics.export.dynatrace.api-token=YOUR_TOKEN\nmanagement.metrics.export.dynatrace.v1.device-id=YOUR_DEVICE_ID\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n dynatrace:\n uri: "https://{your-environment-id}.live.dynatrace.com"\n api-token: "YOUR_TOKEN"\n v1:\n device-id: "YOUR_DEVICE_ID"\n')])])]),a("p",[e._v("对于 V1API,你必须指定没有路径的基本环境 URI,因为 V1 端点路径是自动添加的。")]),e._v(" "),a("h5",{attrs:{id:"与版本无关的设置"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#与版本无关的设置"}},[e._v("#")]),e._v(" 与版本无关的设置")]),e._v(" "),a("p",[e._v("除了 API 端点和令牌,你还可以更改将指标发送到 Dynatrace 的时间间隔。默认的导出间隔是"),a("code",[e._v("60s")]),e._v("。以下示例将导出间隔设置为 30 秒:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.dynatrace.step=30s\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n dynatrace:\n step: "30s"\n')])])]),a("p",[e._v("你可以在"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/dynatrace",target:"_blank",rel:"noopener noreferrer"}},[e._v("千分尺文档"),a("OutboundLink")],1),e._v("中找到有关如何为千分尺设置 Dynatrace Exporter 的更多信息。")]),e._v(" "),a("h4",{attrs:{id:"_6-2-5-弹性"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-5-弹性"}},[e._v("#")]),e._v(" 6.2.5.弹性")]),e._v(" "),a("p",[e._v("默认情况下,指标导出到在本地机器上运行的"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/elastic",target:"_blank",rel:"noopener noreferrer"}},[e._v("Elastic"),a("OutboundLink")],1),e._v("。你可以使用以下属性提供要使用的 Elastic 服务器的位置:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.elastic.host=https://elastic.example.com:8086\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n elastic:\n host: "https://elastic.example.com:8086"\n')])])]),a("h4",{attrs:{id:"_6-2-6-神经节"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-6-神经节"}},[e._v("#")]),e._v(" 6.2.6.神经节")]),e._v(" "),a("p",[e._v("默认情况下,指标导出到在本地机器上运行的"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/ganglia",target:"_blank",rel:"noopener noreferrer"}},[e._v("Ganglia"),a("OutboundLink")],1),e._v("。你可以提供"),a("a",{attrs:{href:"http://ganglia.sourceforge.net",target:"_blank",rel:"noopener noreferrer"}},[e._v("Ganglia 服务器"),a("OutboundLink")],1),e._v("主机和端口,如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.ganglia.host=ganglia.example.com\nmanagement.metrics.export.ganglia.port=9649\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n ganglia:\n host: "ganglia.example.com"\n port: 9649\n')])])]),a("h4",{attrs:{id:"_6-2-7-石墨"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-7-石墨"}},[e._v("#")]),e._v(" 6.2.7.石墨")]),e._v(" "),a("p",[e._v("默认情况下,指标导出到在本地机器上运行的"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/graphite",target:"_blank",rel:"noopener noreferrer"}},[e._v("Graphite"),a("OutboundLink")],1),e._v("。你可以提供"),a("a",{attrs:{href:"https://graphiteapp.org",target:"_blank",rel:"noopener noreferrer"}},[e._v("石墨服务器"),a("OutboundLink")],1),e._v("主机和端口,如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.graphite.host=graphite.example.com\nmanagement.metrics.export.graphite.port=9004\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n graphite:\n host: "graphite.example.com"\n port: 9004\n')])])]),a("p",[e._v("Micrometer 提供了一个默认的"),a("code",[e._v("HierarchicalNameMapper")]),e._v(",它控制一个维度表 ID 是"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/graphite#_hierarchical_name_mapping",target:"_blank",rel:"noopener noreferrer"}},[e._v("映射到平面层次结构名称"),a("OutboundLink")],1),e._v("的方式。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("要控制此行为,请定义你的"),a("code",[e._v("GraphiteMeterRegistry")]),e._v("并提供你自己的"),a("code",[e._v("HierarchicalNameMapper")]),e._v("。"),a("br"),e._v("提供自动配置的"),a("code",[e._v("GraphiteConfig")]),e._v("和"),a("code",[e._v("Clock")]),e._v("bean,除非你定义自己的:"),a("br"),a("br")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_6-2-8-humio"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-8-humio"}},[e._v("#")]),e._v(" 6.2.8.Humio")]),e._v(" "),a("p",[e._v("默认情况下,Humio 注册中心会定期将指标推到"),a("a",{attrs:{href:"https://cloud.humio.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("cloud.humio.com"),a("OutboundLink")],1),e._v("。要将指标导出到 SaaS"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/humio",target:"_blank",rel:"noopener noreferrer"}},[e._v("Humio"),a("OutboundLink")],1),e._v(",你必须提供你的 API 令牌:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.humio.api-token=YOUR_TOKEN\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n humio:\n api-token: "YOUR_TOKEN"\n')])])]),a("p",[e._v("你还应该配置一个或多个标记,以标识将指标推送到的数据源:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.humio.tags.alpha=a\nmanagement.metrics.export.humio.tags.bravo=b\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n humio:\n tags:\n alpha: "a"\n bravo: "b"\n')])])]),a("h4",{attrs:{id:"_6-2-9-涌入"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-9-涌入"}},[e._v("#")]),e._v(" 6.2.9.涌入")]),e._v(" "),a("p",[e._v("默认情况下,指标将导出到使用默认配置在本地计算机上运行的"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/influx",target:"_blank",rel:"noopener noreferrer"}},[e._v("Influx"),a("OutboundLink")],1),e._v("V1 实例。要将指标导出到 InfluxDB V2,请配置"),a("code",[e._v("org")]),e._v("、"),a("code",[e._v("bucket")]),e._v("以及用于编写指标的身份验证"),a("code",[e._v("token")]),e._v("。你可以通过以下方式提供要使用的"),a("a",{attrs:{href:"https://www.influxdata.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("influg 服务器"),a("OutboundLink")],1),e._v("的位置:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.influx.uri=https://influx.example.com:8086\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n influx:\n uri: "https://influx.example.com:8086"\n')])])]),a("h4",{attrs:{id:"_6-2-10-jmx"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-10-jmx"}},[e._v("#")]),e._v(" 6.2.10.JMX")]),e._v(" "),a("p",[e._v("Micrometer 提供了到"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/jmx",target:"_blank",rel:"noopener noreferrer"}},[e._v("JMX"),a("OutboundLink")],1),e._v("的层次映射,主要是作为一种本地查看度量的廉价且便携的方式。默认情况下,指标导出到"),a("code",[e._v("metrics")]),e._v("JMX 域。你可以通过以下方式提供要使用的域:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.jmx.domain=com.example.app.metrics\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n jmx:\n domain: "com.example.app.metrics"\n')])])]),a("p",[e._v("Micrometer 提供了一个默认的"),a("code",[e._v("HierarchicalNameMapper")]),e._v(",它控制一个维度表 ID 是"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/jmx#_hierarchical_name_mapping",target:"_blank",rel:"noopener noreferrer"}},[e._v("映射到平面层次结构名称"),a("OutboundLink")],1),e._v("的方式。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("要控制此行为,请定义你的"),a("code",[e._v("JmxMeterRegistry")]),e._v("并提供你自己的"),a("code",[e._v("HierarchicalNameMapper")]),e._v("。"),a("br"),e._v("提供自动配置的"),a("code",[e._v("JmxConfig")]),e._v("和"),a("code",[e._v("Clock")]),e._v("bean,除非你自己定义:"),a("br"),a("br")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_6-2-11-kairosdb"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-11-kairosdb"}},[e._v("#")]),e._v(" 6.2.11.KairosDB")]),e._v(" "),a("p",[e._v("默认情况下,指标导出到在本地机器上运行的"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/kairos",target:"_blank",rel:"noopener noreferrer"}},[e._v("KairosDB"),a("OutboundLink")],1),e._v("。你可以通过以下方式提供要使用的"),a("a",{attrs:{href:"https://kairosdb.github.io/",target:"_blank",rel:"noopener noreferrer"}},[e._v("KaiRosDB 服务器"),a("OutboundLink")],1),e._v("的位置:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.kairos.uri=https://kairosdb.example.com:8080/api/v1/datapoints\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n kairos:\n uri: "https://kairosdb.example.com:8080/api/v1/datapoints"\n')])])]),a("h4",{attrs:{id:"_6-2-12-新遗迹"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-12-新遗迹"}},[e._v("#")]),e._v(" 6.2.12.新遗迹")]),e._v(" "),a("p",[e._v("一个新的 Relic 注册中心定期将指标推到"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/new-relic",target:"_blank",rel:"noopener noreferrer"}},[e._v("New Relic"),a("OutboundLink")],1),e._v("。要将指标导出到"),a("a",{attrs:{href:"https://newrelic.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("New Relic"),a("OutboundLink")],1),e._v(",你必须提供你的 API 密钥和帐户 ID:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.newrelic.api-key=YOUR_KEY\nmanagement.metrics.export.newrelic.account-id=YOUR_ACCOUNT_ID\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n newrelic:\n api-key: "YOUR_KEY"\n account-id: "YOUR_ACCOUNT_ID"\n')])])]),a("p",[e._v("你还可以更改将指标发送到 New Relic 的时间间隔:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.newrelic.step=30s\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n newrelic:\n step: "30s"\n')])])]),a("p",[e._v("默认情况下,度量是通过 REST 调用发布的,但是如果你在 Classpath 上有 Java Agent API,那么你也可以使用它:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.newrelic.client-provider-type=insights-agent\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n newrelic:\n client-provider-type: "insights-agent"\n')])])]),a("p",[e._v("最后,你可以通过定义自己的"),a("code",[e._v("NewRelicClientProvider")]),e._v(" Bean 来获得完全控制。")]),e._v(" "),a("h4",{attrs:{id:"_6-2-13-prometheus"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-13-prometheus"}},[e._v("#")]),e._v(" 6.2.13.Prometheus")]),e._v(" "),a("p",[a("a",{attrs:{href:"https://micrometer.io/docs/registry/prometheus",target:"_blank",rel:"noopener noreferrer"}},[e._v("Prometheus"),a("OutboundLink")],1),e._v("期望抓取或轮询单个应用程序实例以获取指标。 Spring 引导在"),a("code",[e._v("/actuator/prometheus")]),e._v("处提供执行器端点,以呈现具有适当格式的"),a("a",{attrs:{href:"https://prometheus.io",target:"_blank",rel:"noopener noreferrer"}},[e._v("普罗米修斯刮"),a("OutboundLink")],1),e._v("。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("默认情况下,端点不可用,必须公开。有关更多详细信息,请参见"),a("a",{attrs:{href:"#actuator.endpoints.exposing"}},[e._v("公开端点")]),e._v("。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("下面的示例"),a("code",[e._v("scrape_config")]),e._v("将添加到"),a("code",[e._v("prometheus.yml")]),e._v(":")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('scrape_configs:\n - job_name: "spring"\n metrics_path: "/actuator/prometheus"\n static_configs:\n - targets: ["HOST:PORT"]\n')])])]),a("p",[e._v("对于可能存在的时间不够长而无法被抓取的临时或批处理作业,可以使用"),a("a",{attrs:{href:"https://github.com/prometheus/pushgateway",target:"_blank",rel:"noopener noreferrer"}},[e._v("普罗米修斯 · 普什盖特"),a("OutboundLink")],1),e._v("支持将度量公开给普罗米修斯。要启用 Prometheus PushGateway 支持,请在项目中添加以下依赖项:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("\n io.prometheus\n simpleclient_pushgateway\n\n")])])]),a("p",[e._v("当 Classpath 上存在 Prometheus PushGateway 依赖项并且"),a("code",[e._v("management.metrics.export.prometheus.pushgateway.enabled")]),e._v("属性设置为"),a("code",[e._v("true")]),e._v("时,将自动配置"),a("code",[e._v("PrometheusPushGatewayManager")]),e._v(" Bean。这管理了将指标推送到 Prometheus PushGateway 的过程。")]),e._v(" "),a("p",[e._v("你可以使用"),a("code",[e._v("management.metrics.export.prometheus.pushgateway")]),e._v("下的属性来调优"),a("code",[e._v("PrometheusPushGatewayManager")]),e._v("。对于高级配置,还可以提供自己的"),a("code",[e._v("PrometheusPushGatewayManager")]),e._v(" Bean。")]),e._v(" "),a("h4",{attrs:{id:"_6-2-14-signalfx"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-14-signalfx"}},[e._v("#")]),e._v(" 6.2.14.SignalFX")]),e._v(" "),a("p",[e._v("SignalFX Registry 定期将指标推到"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/signalFx",target:"_blank",rel:"noopener noreferrer"}},[e._v("SignalFx"),a("OutboundLink")],1),e._v("。要将指标导出到"),a("a",{attrs:{href:"https://www.signalfx.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("SignalFx"),a("OutboundLink")],1),e._v(",你必须提供访问令牌:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.signalfx.access-token=YOUR_ACCESS_TOKEN\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n signalfx:\n access-token: "YOUR_ACCESS_TOKEN"\n')])])]),a("p",[e._v("你还可以更改将指标发送到 SignalFX 的间隔时间:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.signalfx.step=30s\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n signalfx:\n step: "30s"\n')])])]),a("h4",{attrs:{id:"_6-2-15-简单"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-15-简单"}},[e._v("#")]),e._v(" 6.2.15.简单")]),e._v(" "),a("p",[e._v("Micrometer 附带了一个简单的内存后端,如果没有配置其他注册中心,该后端将自动用作后备。这让你看到在"),a("a",{attrs:{href:"#actuator.metrics.endpoint"}},[e._v("指标端点")]),e._v("中收集了哪些指标。")]),e._v(" "),a("p",[e._v("一旦你使用任何其他可用的后端,内存中的后端就会禁用它自己。你还可以显式地禁用它:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.simple.enabled=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n metrics:\n export:\n simple:\n enabled: false\n")])])]),a("h4",{attrs:{id:"_6-2-16-stackdriver"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-16-stackdriver"}},[e._v("#")]),e._v(" 6.2.16.Stackdriver")]),e._v(" "),a("p",[e._v("StackDriver 注册表定期将指标推到"),a("a",{attrs:{href:"https://cloud.google.com/stackdriver/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Stackdriver"),a("OutboundLink")],1),e._v("。要将指标导出到 SaaS"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/stackdriver",target:"_blank",rel:"noopener noreferrer"}},[e._v("Stackdriver"),a("OutboundLink")],1),e._v(",你必须提供你的 Google Cloud 项目 ID:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.stackdriver.project-id=my-project\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n stackdriver:\n project-id: "my-project"\n')])])]),a("p",[e._v("你还可以更改将指标发送到 StackDriver 的间隔时间:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.stackdriver.step=30s\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n stackdriver:\n step: "30s"\n')])])]),a("h4",{attrs:{id:"_6-2-17-统计-d"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-17-统计-d"}},[e._v("#")]),e._v(" 6.2.17.统计 d")]),e._v(" "),a("p",[e._v("STATSD 注册中心急切地将 UDP 上的指标推送到 STATSD 代理。默认情况下,指标被导出到在本地机器上运行的"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/statsD",target:"_blank",rel:"noopener noreferrer"}},[e._v("StatsD"),a("OutboundLink")],1),e._v("代理。你可以使用以下方法提供要使用的 STATSD 代理主机、端口和协议:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.statsd.host=statsd.example.com\nmanagement.metrics.export.statsd.port=9125\nmanagement.metrics.export.statsd.protocol=udp\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n statsd:\n host: "statsd.example.com"\n port: 9125\n protocol: "udp"\n')])])]),a("p",[e._v("你也可以将 STATSD 行协议更改为使用(默认为 Datadog):")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.statsd.flavor=etsy\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n statsd:\n flavor: "etsy"\n')])])]),a("h4",{attrs:{id:"_6-2-18-波阵面"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-2-18-波阵面"}},[e._v("#")]),e._v(" 6.2.18.波阵面")]),e._v(" "),a("p",[e._v("Wavefront 注册中心定期将指标推到"),a("a",{attrs:{href:"https://micrometer.io/docs/registry/wavefront",target:"_blank",rel:"noopener noreferrer"}},[e._v("Wavefront"),a("OutboundLink")],1),e._v("。如果要直接将指标导出到"),a("a",{attrs:{href:"https://www.wavefront.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Wavefront"),a("OutboundLink")],1),e._v(",则必须提供你的 API 令牌:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.wavefront.api-token=YOUR_API_TOKEN\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n wavefront:\n api-token: "YOUR_API_TOKEN"\n')])])]),a("p",[e._v("或者,你可以在你的环境中使用 Wavefront 侧车或内部代理将度量数据转发到 Wavefront API 主机:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.wavefront.uri=proxy://localhost:2878\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n wavefront:\n uri: "proxy://localhost:2878"\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果将指标发布到 Wavefront 代理(如"),a("a",{attrs:{href:"https://docs.wavefront.com/proxies_installing.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Wavefront 文档"),a("OutboundLink")],1),e._v("中所述),则主机必须为"),a("code",[e._v("proxy://HOST:PORT")]),e._v("格式。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("你还可以更改将指标发送到 Wavefront 的间隔时间:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.export.wavefront.step=30s\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n export:\n wavefront:\n step: "30s"\n')])])]),a("h3",{attrs:{id:"_6-3-支持的度量和计量器"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-支持的度量和计量器"}},[e._v("#")]),e._v(" 6.3.支持的度量和计量器")]),e._v(" "),a("p",[e._v("Spring Boot 为各种各样的技术提供了自动仪表注册。在大多数情况下,默认值提供了可以发布到任何受支持的监视系统的合理指标。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-1-jvm-度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-1-jvm-度量"}},[e._v("#")]),e._v(" 6.3.1.JVM 度量")]),e._v(" "),a("p",[e._v("自动配置通过使用核心 Micrometer 类来实现 JVM 度量。JVM 度量以"),a("code",[e._v("jvm.")]),e._v("度量名称发布。")]),e._v(" "),a("p",[e._v("提供了以下 JVM 指标:")]),e._v(" "),a("ul",[a("li",[a("p",[e._v("各种内存和缓冲池详细信息")])]),e._v(" "),a("li",[a("p",[e._v("与垃圾收集相关的统计信息")])]),e._v(" "),a("li",[a("p",[e._v("线程利用率")])]),e._v(" "),a("li",[a("p",[e._v("加载和卸载的类的数量")])])]),e._v(" "),a("h4",{attrs:{id:"_6-3-2-系统度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-2-系统度量"}},[e._v("#")]),e._v(" 6.3.2.系统度量")]),e._v(" "),a("p",[e._v("自动配置通过使用核心微米表类来实现系统度量。系统度量在"),a("code",[e._v("system.")]),e._v("、"),a("code",[e._v("process.")]),e._v("和"),a("code",[e._v("disk.")]),e._v("米表名称下发布。")]),e._v(" "),a("p",[e._v("提供了以下系统指标:")]),e._v(" "),a("ul",[a("li",[a("p",[e._v("CPU 度量")])]),e._v(" "),a("li",[a("p",[e._v("文件描述符度量")])]),e._v(" "),a("li",[a("p",[e._v("正常运行时间指标(应用程序运行的时间和绝对启动时间的固定指标)")])]),e._v(" "),a("li",[a("p",[e._v("可用磁盘空间")])])]),e._v(" "),a("h4",{attrs:{id:"_6-3-3-应用程序启动度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-3-应用程序启动度量"}},[e._v("#")]),e._v(" 6.3.3.应用程序启动度量")]),e._v(" "),a("p",[e._v("自动配置公开应用程序启动时间指标:")]),e._v(" "),a("ul",[a("li",[a("p",[a("code",[e._v("application.started.time")]),e._v(":启动应用程序所需的时间。")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("application.ready.time")]),e._v(":应用程序准备好服务请求所需的时间。")])])]),e._v(" "),a("p",[e._v("度量由应用程序类的完全限定名称标记。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-4-记录器指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-4-记录器指标"}},[e._v("#")]),e._v(" 6.3.4.记录器指标")]),e._v(" "),a("p",[e._v("自动配置可以为 logback 和 log4j2 启用事件度量。详细信息在"),a("code",[e._v("log4j2.events.")]),e._v("或"),a("code",[e._v("logback.events.")]),e._v("表名称下发布。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-5-任务执行和调度指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-5-任务执行和调度指标"}},[e._v("#")]),e._v(" 6.3.5.任务执行和调度指标")]),e._v(" "),a("p",[e._v("自动配置允许对所有可用的"),a("code",[e._v("ThreadPoolTaskExecutor")]),e._v("和"),a("code",[e._v("ThreadPoolTaskScheduler")]),e._v("bean 进行插装,只要下面的"),a("code",[e._v("ThreadPoolExecutor")]),e._v("可用。度量由执行器的名称标记,该名称来自 Bean 名称。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-6-spring-mvc-度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-6-spring-mvc-度量"}},[e._v("#")]),e._v(" 6.3.6. Spring MVC 度量")]),e._v(" "),a("p",[e._v("自动配置使所有由 Spring MVC 控制器和功能处理程序处理的请求的检测成为可能。默认情况下,度量值是用名称"),a("code",[e._v("http.server.requests")]),e._v("生成的。你可以通过设置"),a("code",[e._v("management.metrics.web.server.request.metric-name")]),e._v("属性来定制名称。")]),e._v(" "),a("p",[a("code",[e._v("@Timed")]),e._v("批注在"),a("code",[e._v("@Controller")]),e._v("类和"),a("code",[e._v("@RequestMapping")]),e._v("方法上都是支持的(详见"),a("a",{attrs:{href:"#actuator.metrics.supported.timed-annotation"}},[e._v("@ 定时注释支持")]),e._v(")。如果不想记录所有 Spring MVC 请求的度量,则可以将"),a("code",[e._v("management.metrics.web.server.request.autotime.enabled")]),e._v("设置为"),a("code",[e._v("false")]),e._v(",并专门使用"),a("code",[e._v("@Timed")]),e._v("注释。")]),e._v(" "),a("p",[e._v("默认情况下, Spring MVC 相关度量标记有以下信息:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Tag")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("exception")])]),e._v(" "),a("td",[e._v("处理请求时引发的任何异常的简单类名。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("method")])]),e._v(" "),a("td",[e._v("请求的方法(例如,"),a("code",[e._v("GET")]),e._v("或"),a("code",[e._v("POST")]),e._v(")")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("outcome")])]),e._v(" "),a("td",[e._v("请求的结果,基于响应的状态代码。"),a("br"),e._v("1xx 是"),a("code",[e._v("INFORMATIONAL")]),e._v(",2xx 是"),a("code",[e._v("SUCCESS")]),e._v(",3xx 是"),a("code",[e._v("REDIRECTION")]),e._v(",4xx 是"),a("code",[e._v("CLIENT_ERROR")]),e._v(",5xx 是"),a("code",[e._v("SERVER_ERROR")])])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("status")])]),e._v(" "),a("td",[e._v("响应的 HTTP 状态代码(例如,"),a("code",[e._v("200")]),e._v("或"),a("code",[e._v("500")]),e._v(")")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("uri")])]),e._v(" "),a("td",[e._v("如果可能的话,在变量替换之前提供请求的 URI 模板(例如,"),a("code",[e._v("/api/person/{id}")]),e._v(")")])])])]),e._v(" "),a("p",[e._v("要添加到默认标记中,请提供一个或多个实现"),a("code",[e._v("@Bean")]),e._v("的"),a("code",[e._v("WebMvcTagsContributor")]),e._v("s。要替换默认标记,请提供一个实现"),a("code",[e._v("WebMvcTagsProvider")]),e._v("的"),a("code",[e._v("@Bean")]),e._v("。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("在某些情况下,在 Web 控制器中处理的异常不被记录为请求度量标记。"),a("br"),e._v("应用程序可以通过"),a("RouterLink",{attrs:{to:"/spring-boot/web.html#web.servlet.spring-mvc.error-handling"}},[e._v("将已处理的异常设置为请求属性")]),e._v("OPT 并记录异常。")],1)])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_6-3-7-spring-webflux-度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-7-spring-webflux-度量"}},[e._v("#")]),e._v(" 6.3.7. Spring WebFlux 度量")]),e._v(" "),a("p",[e._v("自动配置允许检测由 Spring WebFlux 控制器和功能处理程序处理的所有请求。默认情况下,度量值以"),a("code",[e._v("http.server.requests")]),e._v("的名称生成。你可以通过设置"),a("code",[e._v("management.metrics.web.server.request.metric-name")]),e._v("属性来定制名称。")]),e._v(" "),a("p",[a("code",[e._v("@Timed")]),e._v("批注在"),a("code",[e._v("@Controller")]),e._v("类和"),a("code",[e._v("@RequestMapping")]),e._v("方法上都是支持的(详见"),a("a",{attrs:{href:"#actuator.metrics.supported.timed-annotation"}},[e._v("@ 定时注释支持")]),e._v(")。如果不想记录所有 Spring WebFlux 请求的度量,则可以将"),a("code",[e._v("management.metrics.web.server.request.autotime.enabled")]),e._v("设置为"),a("code",[e._v("false")]),e._v(",并专门使用"),a("code",[e._v("@Timed")]),e._v("注释。")]),e._v(" "),a("p",[e._v("默认情况下,WebFlux 相关度量标记有以下信息:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Tag")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("exception")])]),e._v(" "),a("td",[e._v("处理请求时引发的任何异常的简单类名。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("method")])]),e._v(" "),a("td",[e._v("请求的方法(例如,"),a("code",[e._v("GET")]),e._v("或"),a("code",[e._v("POST")]),e._v(")")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("outcome")])]),e._v(" "),a("td",[e._v("请求的结果,基于响应的状态代码。"),a("br"),e._v("1xx 是"),a("code",[e._v("INFORMATIONAL")]),e._v(",2xx 是"),a("code",[e._v("SUCCESS")]),e._v(",3xx 是"),a("code",[e._v("REDIRECTION")]),e._v(",4xx 是"),a("code",[e._v("CLIENT_ERROR")]),e._v(",5xx 是"),a("code",[e._v("SERVER_ERROR")])])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("status")])]),e._v(" "),a("td",[e._v("响应的 HTTP 状态代码(例如,"),a("code",[e._v("200")]),e._v("或"),a("code",[e._v("500")]),e._v(")")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("uri")])]),e._v(" "),a("td",[e._v("如果可能的话,在变量替换之前提供请求的 URI 模板(例如,"),a("code",[e._v("/api/person/{id}")]),e._v(")")])])])]),e._v(" "),a("p",[e._v("要添加到默认标记中,请提供一个或多个实现"),a("code",[e._v("WebFluxTagsContributor")]),e._v("的 bean。要替换默认标记,请提供实现"),a("code",[e._v("WebFluxTagsProvider")]),e._v("的 Bean。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("在某些情况下,在控制器和处理程序函数中处理的异常不被记录为请求度量标记。"),a("br"),e._v("应用程序可以通过"),a("RouterLink",{attrs:{to:"/spring-boot/web.html#web.reactive.webflux.error-handling"}},[e._v("将已处理的异常设置为请求属性")]),e._v("OPT 和记录异常。")],1)])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_6-3-8-泽西服务器指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-8-泽西服务器指标"}},[e._v("#")]),e._v(" 6.3.8.泽西服务器指标")]),e._v(" "),a("p",[e._v("自动配置支持对 Jersey JAX-RS 实现处理的所有请求进行检测。默认情况下,度量值是用名称"),a("code",[e._v("http.server.requests")]),e._v("生成的。你可以通过设置"),a("code",[e._v("management.metrics.web.server.request.metric-name")]),e._v("属性来定制名称。")]),e._v(" "),a("p",[a("code",[e._v("@Timed")]),e._v("在请求处理类和方法上支持注释(有关详细信息,请参见"),a("a",{attrs:{href:"#actuator.metrics.supported.timed-annotation"}},[e._v("@ 定时注释支持")]),e._v(")。如果不想记录所有 Jersey 请求的度量,可以将"),a("code",[e._v("management.metrics.web.server.request.autotime.enabled")]),e._v("设置为"),a("code",[e._v("false")]),e._v(",并专门使用"),a("code",[e._v("@Timed")]),e._v("注释。")]),e._v(" "),a("p",[e._v("默认情况下,Jersey Server Metrics 使用以下信息进行标记:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Tag")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("exception")])]),e._v(" "),a("td",[e._v("处理请求时引发的任何异常的简单类名。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("method")])]),e._v(" "),a("td",[e._v("请求的方法(例如,"),a("code",[e._v("GET")]),e._v("或"),a("code",[e._v("POST")]),e._v(")")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("outcome")])]),e._v(" "),a("td",[e._v("请求的结果,基于响应的状态代码。"),a("br"),e._v("1xx 是"),a("code",[e._v("INFORMATIONAL")]),e._v(",2xx 是"),a("code",[e._v("SUCCESS")]),e._v(",3xx 是"),a("code",[e._v("REDIRECTION")]),e._v(",4xx 是"),a("code",[e._v("CLIENT_ERROR")]),e._v(",5xx 是"),a("code",[e._v("SERVER_ERROR")])])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("status")])]),e._v(" "),a("td",[e._v("响应的 HTTP 状态代码(例如,"),a("code",[e._v("200")]),e._v("或"),a("code",[e._v("500")]),e._v(")")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("uri")])]),e._v(" "),a("td",[e._v("如果可能的话,在变量替换之前提供请求的 URI 模板(例如,"),a("code",[e._v("/api/person/{id}")]),e._v(")")])])])]),e._v(" "),a("p",[e._v("要定制标记,请提供实现"),a("code",[e._v("JerseyTagsProvider")]),e._v("的"),a("code",[e._v("@Bean")]),e._v("。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-9-http-客户端度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-9-http-客户端度量"}},[e._v("#")]),e._v(" 6.3.9.HTTP 客户端度量")]),e._v(" "),a("p",[e._v("Spring 引导执行器管理"),a("code",[e._v("RestTemplate")]),e._v("和"),a("code",[e._v("WebClient")]),e._v("两者的仪表。为此,你必须插入自动配置的生成器,并使用它创建实例:")]),e._v(" "),a("ul",[a("li",[a("p",[a("code",[e._v("RestTemplateBuilder")]),e._v("表示"),a("code",[e._v("RestTemplate")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("WebClient.Builder")]),e._v("表示"),a("code",[e._v("WebClient")])])])]),e._v(" "),a("p",[e._v("你还可以手动应用负责此检测的定制程序,即"),a("code",[e._v("MetricsRestTemplateCustomizer")]),e._v("和"),a("code",[e._v("MetricsWebClientCustomizer")]),e._v("。")]),e._v(" "),a("p",[e._v("默认情况下,度量值以"),a("code",[e._v("http.client.requests")]),e._v("的名称生成。你可以通过设置"),a("code",[e._v("management.metrics.web.client.request.metric-name")]),e._v("属性来定制名称。")]),e._v(" "),a("p",[e._v("默认情况下,由检测过的客户机生成的度量值被标记为以下信息:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Tag")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("clientName")])]),e._v(" "),a("td",[e._v("URI 的主机部分")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("method")])]),e._v(" "),a("td",[e._v("请求的方法(例如,"),a("code",[e._v("GET")]),e._v("或"),a("code",[e._v("POST")]),e._v(")")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("outcome")])]),e._v(" "),a("td",[e._v("请求的结果,基于响应的状态代码。"),a("br"),e._v("1xx 是"),a("code",[e._v("INFORMATIONAL")]),e._v(",2xx 是"),a("code",[e._v("SUCCESS")]),e._v(",3xx 是"),a("code",[e._v("REDIRECTION")]),e._v(",4xx 是"),a("code",[e._v("CLIENT_ERROR")]),e._v(",5xx 是"),a("code",[e._v("SERVER_ERROR")]),e._v("。否则,它是"),a("code",[e._v("UNKNOWN")]),e._v("。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("status")])]),e._v(" "),a("td",[e._v("响应的 HTTP 状态代码(如果可用的话)(例如,"),a("code",[e._v("200")]),e._v("或"),a("code",[e._v("500")]),e._v(")或"),a("code",[e._v("IO_ERROR")]),e._v("在 I/O 问题的情况下。否则,它是"),a("code",[e._v("CLIENT_ERROR")]),e._v("。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("uri")])]),e._v(" "),a("td",[e._v("如果可能的话,在变量替换之前提供请求的 URI 模板(例如,"),a("code",[e._v("/api/person/{id}")]),e._v(")")])])])]),e._v(" "),a("p",[e._v("为了自定义标记,并且根据你对客户机的选择,你可以提供一个"),a("code",[e._v("@Bean")]),e._v("来实现"),a("code",[e._v("RestTemplateExchangeTagsProvider")]),e._v("或"),a("code",[e._v("WebClientExchangeTagsProvider")]),e._v("。在"),a("code",[e._v("RestTemplateExchangeTags")]),e._v("和"),a("code",[e._v("WebClientExchangeTags")]),e._v("中有方便的静态函数。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-10-tomcat-指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-10-tomcat-指标"}},[e._v("#")]),e._v(" 6.3.10. Tomcat 指标")]),e._v(" "),a("p",[e._v("自动配置仅在启用"),a("code",[e._v("MBeanRegistry")]),e._v("时才启用 Tomcat 的插装。默认情况下,"),a("code",[e._v("MBeanRegistry")]),e._v("是禁用的,但是你可以通过将"),a("code",[e._v("server.tomcat.mbeanregistry.enabled")]),e._v("设置为"),a("code",[e._v("true")]),e._v("来启用它。")]),e._v(" "),a("p",[e._v("Tomcat 度量在"),a("code",[e._v("tomcat.")]),e._v("度量名称下发布。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-11-缓存度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-11-缓存度量"}},[e._v("#")]),e._v(" 6.3.11.缓存度量")]),e._v(" "),a("p",[e._v("自动配置允许在启动时检测所有可用的"),a("code",[e._v("Cache")]),e._v("实例,其度量值前缀为"),a("code",[e._v("cache")]),e._v("。缓存检测是针对一组基本的度量标准进行标准化的。另外,特定于缓存的指标也是可用的。")]),e._v(" "),a("p",[e._v("支持以下缓存库:")]),e._v(" "),a("ul",[a("li",[a("p",[e._v("咖啡因")])]),e._v(" "),a("li",[a("p",[e._v("Ehcache2")])]),e._v(" "),a("li",[a("p",[e._v("黑泽尔卡斯特")])]),e._v(" "),a("li",[a("p",[e._v("任何兼容的 JCache(JSR-107)实现")])]),e._v(" "),a("li",[a("p",[e._v("雷迪斯")])])]),e._v(" "),a("p",[e._v("度量由缓存的名称和"),a("code",[e._v("CacheManager")]),e._v("的名称标记,该名称来自 Bean 名称。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("只有在启动时配置的缓存才绑定到注册表。"),a("br"),e._v("对于在缓存配置中未定义的缓存,例如在运行中创建的缓存或在启动阶段之后以编程方式创建的缓存,需要显式的注册。"),a("br"),e._v("提供了"),a("code",[e._v("CacheMetricsRegistrar")]),e._v(" Bean 以使该过程更容易。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_6-3-12-数据源度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-12-数据源度量"}},[e._v("#")]),e._v(" 6.3.12.数据源度量")]),e._v(" "),a("p",[e._v("自动配置允许对所有可用的"),a("code",[e._v("DataSource")]),e._v("对象进行插装,这些对象的度量前缀为"),a("code",[e._v("jdbc.connections")]),e._v("。数据源插装产生的量规表示池中当前活动的、空闲的、最大允许的和最小允许的连接。")]),e._v(" "),a("p",[e._v("度量指标还由基于 Bean 名称计算的"),a("code",[e._v("DataSource")]),e._v("的名称标记。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("默认情况下, Spring boot 为所有受支持的数据源提供元数据。"),a("br"),e._v("如果不支持你喜欢的数据源,你可以添加额外的"),a("code",[e._v("DataSourcePoolMetadataProvider")]),e._v("bean。"),a("br"),e._v("参见"),a("code",[e._v("DataSourcePoolMetadataProvidersConfiguration")]),e._v("示例。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("此外,特定于光的度量以"),a("code",[e._v("hikaricp")]),e._v("前缀公开。每个度量都由池的名称标记(你可以使用"),a("code",[e._v("spring.datasource.name")]),e._v("对其进行控制)。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-13-hibernate-指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-13-hibernate-指标"}},[e._v("#")]),e._v(" 6.3.13. Hibernate 指标")]),e._v(" "),a("p",[e._v("如果"),a("code",[e._v("org.hibernate:hibernate-micrometer")]),e._v("在 Classpath 上,则所有启用了统计信息的 Hibernate "),a("code",[e._v("EntityManagerFactory")]),e._v("实例都将使用一个名为"),a("code",[e._v("hibernate")]),e._v("的度量指标进行检测。")]),e._v(" "),a("p",[e._v("度量还由"),a("code",[e._v("EntityManagerFactory")]),e._v("的名称标记,该名称来自 Bean 名称。")]),e._v(" "),a("p",[e._v("要启用统计信息,标准 JPA 属性"),a("code",[e._v("hibernate.generate_statistics")]),e._v("必须设置为"),a("code",[e._v("true")]),e._v("。你可以在自动配置的"),a("code",[e._v("EntityManagerFactory")]),e._v("上启用该功能:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("spring.jpa.properties[hibernate.generate_statistics]=true\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('spring:\n jpa:\n properties:\n "[hibernate.generate_statistics]": true\n')])])]),a("h4",{attrs:{id:"_6-3-14-spring-数据存储库指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-14-spring-数据存储库指标"}},[e._v("#")]),e._v(" 6.3.14. Spring 数据存储库指标")]),e._v(" "),a("p",[e._v("自动配置使所有 Spring 数据"),a("code",[e._v("Repository")]),e._v("方法调用的检测成为可能。默认情况下,度量值以"),a("code",[e._v("spring.data.repository.invocations")]),e._v("的名称生成。你可以通过设置"),a("code",[e._v("management.metrics.data.repository.metric-name")]),e._v("属性来定制名称。")]),e._v(" "),a("p",[a("code",[e._v("Repository")]),e._v("在"),a("code",[e._v("Repository")]),e._v("类和方法上支持"),a("code",[e._v("EntityManagerFactory")]),e._v("注释(有关详细信息,请参见"),a("a",{attrs:{href:"#actuator.metrics.supported.timed-annotation"}},[e._v("@ 定时注释支持")]),e._v(")。如果不想记录所有"),a("code",[e._v("Repository")]),e._v("调用的度量,则可以将"),a("code",[e._v("management.metrics.data.repository.autotime.enabled")]),e._v("设置为"),a("code",[e._v("false")]),e._v(",并专门使用"),a("code",[e._v("@Timed")]),e._v("注释。")]),e._v(" "),a("p",[e._v("默认情况下,存储库调用相关的度量被标记为以下信息:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Tag")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("repository")])]),e._v(" "),a("td",[e._v("源的简单类名"),a("code",[e._v("Repository")]),e._v("。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("method")])]),e._v(" "),a("td",[e._v("调用的"),a("code",[e._v("Repository")]),e._v("方法的名称。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("state")])]),e._v(" "),a("td",[e._v("结果状态("),a("code",[e._v("SUCCESS")]),e._v(","),a("code",[e._v("ERROR")]),e._v(","),a("code",[e._v("CANCELED")]),e._v(",或"),a("code",[e._v("RUNNING")]),e._v(")。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("exception")])]),e._v(" "),a("td",[e._v("从调用中抛出的任何异常的简单类名。")])])])]),e._v(" "),a("p",[e._v("要替换默认标记,请提供一个实现"),a("code",[e._v("RepositoryTagsProvider")]),e._v("的"),a("code",[e._v("@Bean")]),e._v("。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-15-rabbitmq-度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-15-rabbitmq-度量"}},[e._v("#")]),e._v(" 6.3.15.RabbitMQ 度量")]),e._v(" "),a("p",[e._v("自动配置允许使用名为"),a("code",[e._v("rabbitmq")]),e._v("的度量来检测所有可用的 RabbitMQ 连接工厂。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-16-spring-集成度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-16-spring-集成度量"}},[e._v("#")]),e._v(" 6.3.16. Spring 集成度量")]),e._v(" "),a("p",[e._v("Spring 只要"),a("code",[e._v("MeterRegistry")]),e._v(" Bean 可用,集成就会自动提供"),a("a",{attrs:{href:"https://docs.spring.io/spring-integration/docs/5.5.9/reference/html/system-management.html#micrometer-integration",target:"_blank",rel:"noopener noreferrer"}},[e._v("千分尺支持"),a("OutboundLink")],1),e._v("。度量以"),a("code",[e._v("spring.integration.")]),e._v("度量名称发布。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-17-卡夫卡指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-17-卡夫卡指标"}},[e._v("#")]),e._v(" 6.3.17.卡夫卡指标")]),e._v(" "),a("p",[e._v("自动配置寄存器"),a("code",[e._v("MicrometerConsumerListener")]),e._v("和"),a("code",[e._v("MicrometerProducerListener")]),e._v("分别用于自动配置的消费者工厂和生产者工厂。它还将"),a("code",[e._v("KafkaStreamsMicrometerListener")]),e._v("注册为"),a("code",[e._v("StreamsBuilderFactoryBean")]),e._v("。有关更多详细信息,请参见 Spring Kafka 文档的"),a("a",{attrs:{href:"https://docs.spring.io/spring-kafka/docs/2.8.3/reference/html/#micrometer-native",target:"_blank",rel:"noopener noreferrer"}},[e._v("千分尺本机度量"),a("OutboundLink")],1),e._v("部分。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-18-mongodb-度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-18-mongodb-度量"}},[e._v("#")]),e._v(" 6.3.18.MongoDB 度量")]),e._v(" "),a("p",[e._v("本节简要介绍 MongoDB 的可用度量。")]),e._v(" "),a("h5",{attrs:{id:"mongodb-命令度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#mongodb-命令度量"}},[e._v("#")]),e._v(" MongoDB 命令度量")]),e._v(" "),a("p",[e._v("自动配置寄存器"),a("code",[e._v("MongoMetricsCommandListener")]),e._v("与自动配置的"),a("code",[e._v("MongoClient")]),e._v("。")]),e._v(" "),a("p",[e._v("为发出给底层 MongoDB 驱动程序的每个命令创建一个名为"),a("code",[e._v("mongodb.driver.commands")]),e._v("的计时器度量。默认情况下,每个度量标准都带有以下信息:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Tag")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("command")])]),e._v(" "),a("td",[e._v("发出的命令的名称。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("cluster.id")])]),e._v(" "),a("td",[e._v("将命令发送到的集群的标识符。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("server.address")])]),e._v(" "),a("td",[e._v("该命令被发送到的服务器的地址。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("status")])]),e._v(" "),a("td",[e._v("命令的结果("),a("code",[e._v("SUCCESS")]),e._v("或"),a("code",[e._v("FAILED")]),e._v(")。")])])])]),e._v(" "),a("p",[e._v("要替换默认的度量标记,请定义"),a("code",[e._v("MongoCommandTagsProvider")]),e._v(" Bean,如下例所示:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("import io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCommandTagsProviderConfiguration {\n\n @Bean\n public MongoCommandTagsProvider customCommandTagsProvider() {\n return new CustomCommandTagsProvider();\n }\n\n}\n\n")])])]),a("p",[e._v("要禁用自动配置的命令度量,请设置以下属性:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.mongo.command.enabled=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n metrics:\n mongo:\n command:\n enabled: false\n")])])]),a("h5",{attrs:{id:"mongodb-连接池指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#mongodb-连接池指标"}},[e._v("#")]),e._v(" MongoDB 连接池指标")]),e._v(" "),a("p",[e._v("自动配置寄存器"),a("code",[e._v("MongoMetricsConnectionPoolListener")]),e._v("与自动配置的"),a("code",[e._v("MongoClient")]),e._v("。")]),e._v(" "),a("p",[e._v("为连接池创建了以下度量指标:")]),e._v(" "),a("ul",[a("li",[a("p",[a("code",[e._v("mongodb.driver.pool.size")]),e._v("报告连接池的当前大小,包括空闲成员和正在使用的成员。")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("mongodb.driver.pool.checkedout")]),e._v("报告当前使用的连接数。")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("mongodb.driver.pool.waitqueuesize")]),e._v("报告池中连接的等待队列的当前大小。")])])]),e._v(" "),a("p",[e._v("默认情况下,每个度量标准都带有以下信息:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Tag")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("cluster.id")])]),e._v(" "),a("td",[e._v("连接池对应的群集的标识符。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("server.address")])]),e._v(" "),a("td",[e._v("连接池对应的服务器的地址。")])])])]),e._v(" "),a("p",[e._v("要替换默认的度量标记,请定义"),a("code",[e._v("MongoConnectionPoolTagsProvider")]),e._v(" Bean:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("import io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyConnectionPoolTagsProviderConfiguration {\n\n @Bean\n public MongoConnectionPoolTagsProvider customConnectionPoolTagsProvider() {\n return new CustomConnectionPoolTagsProvider();\n }\n\n}\n\n")])])]),a("p",[e._v("要禁用自动配置的连接池指标,请设置以下属性:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.mongo.connectionpool.enabled=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n metrics:\n mongo:\n connectionpool:\n enabled: false\n")])])]),a("h4",{attrs:{id:"_6-3-19-jetty-指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-19-jetty-指标"}},[e._v("#")]),e._v(" 6.3.19. Jetty 指标")]),e._v(" "),a("p",[e._v("通过使用 Micrometer 的"),a("code",[e._v("JettyServerThreadPoolMetrics")]),e._v(",自动配置绑定了 Jetty 的"),a("code",[e._v("ThreadPool")]),e._v("的度量。 Jetty 的"),a("code",[e._v("Connector")]),e._v("实例的指标通过使用千分尺的"),a("code",[e._v("JettyConnectionMetrics")]),e._v("绑定,并且,当"),a("code",[e._v("server.ssl.enabled")]),e._v("设置为"),a("code",[e._v("true")]),e._v("时,千分尺的"),a("code",[e._v("JettySslHandshakeMetrics")]),e._v("。")]),e._v(" "),a("h4",{attrs:{id:"_6-3-20-定时注释支持"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-20-定时注释支持"}},[e._v("#")]),e._v(" 6.3.20.@ 定时注释支持")]),e._v(" "),a("p",[e._v("你可以使用"),a("code",[e._v("@Timed")]),e._v("包中的"),a("code",[e._v("io.micrometer.core.annotation")]),e._v("注释以及前面描述的几种受支持的技术。如果支持,可以在类级别或方法级别使用注释。")]),e._v(" "),a("p",[e._v("例如,下面的代码显示了如何使用注释来检验"),a("code",[e._v("@RestController")]),e._v("中的所有请求映射:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('import java.util.List;\n\nimport io.micrometer.core.annotation.Timed;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@Timed\npublic class MyController {\n\n @GetMapping("/api/addresses")\n public List
listAddress() {\n return ...\n }\n\n @GetMapping("/api/people")\n public List listPeople() {\n return ...\n }\n\n}\n\n')])])]),a("p",[e._v("如果你只想使用一个映射,那么可以使用方法上的注释,而不是类:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('import java.util.List;\n\nimport io.micrometer.core.annotation.Timed;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class MyController {\n\n @GetMapping("/api/addresses")\n public List
listAddress() {\n return ...\n }\n\n @GetMapping("/api/people")\n @Timed\n public List listPeople() {\n return ...\n }\n\n}\n\n')])])]),a("p",[e._v("如果你想更改特定方法的时间细节,还可以合并类级和方法级注释:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('import java.util.List;\n\nimport io.micrometer.core.annotation.Timed;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@Timed\npublic class MyController {\n\n @GetMapping("/api/addresses")\n public List
listAddress() {\n return ...\n }\n\n @GetMapping("/api/people")\n @Timed(extraTags = { "region", "us-east-1" })\n @Timed(value = "all.people", longTask = true)\n public List listPeople() {\n return ...\n }\n\n}\n\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("带有"),a("code",[e._v("@Timed")]),e._v("注释的"),a("code",[e._v("longTask = true")]),e._v("将为该方法启用一个长任务计时器。长任务计时器需要一个单独的度量名称,并且可以堆叠一个短任务计时器。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_6-3-21-redis-度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-3-21-redis-度量"}},[e._v("#")]),e._v(" 6.3.21.Redis 度量")]),e._v(" "),a("p",[e._v("自动配置寄存器"),a("code",[e._v("MicrometerCommandLatencyRecorder")]),e._v("用于自动配置的"),a("code",[e._v("LettuceConnectionFactory")]),e._v("。有关更多详细信息,请参见生菜文档的"),a("a",{attrs:{href:"https://lettuce.io/core/6.1.6.RELEASE/reference/index.html#command.latency.metrics.micrometer",target:"_blank",rel:"noopener noreferrer"}},[e._v("千分尺计量部分"),a("OutboundLink")],1),e._v("。")]),e._v(" "),a("h3",{attrs:{id:"_6-4-注册自定义度量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-4-注册自定义度量"}},[e._v("#")]),e._v(" 6.4.注册自定义度量")]),e._v(" "),a("p",[e._v("要注册自定义度量,请将"),a("code",[e._v("MeterRegistry")]),e._v("插入到组件中:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('import io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tags;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n private final Dictionary dictionary;\n\n public MyBean(MeterRegistry registry) {\n this.dictionary = Dictionary.load();\n registry.gauge("dictionary.size", Tags.empty(), this.dictionary.getWords().size());\n }\n\n}\n\n')])])]),a("p",[e._v("如果你的指标依赖于其他 bean,我们建议你使用"),a("code",[e._v("MeterBinder")]),e._v("来注册它们:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('import io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.binder.MeterBinder;\n\nimport org.springframework.context.annotation.Bean;\n\npublic class MyMeterBinderConfiguration {\n\n @Bean\n public MeterBinder queueSize(Queue queue) {\n return (registry) -> Gauge.builder("queueSize", queue::size).register(registry);\n }\n\n}\n\n')])])]),a("p",[e._v("使用"),a("code",[e._v("MeterBinder")]),e._v("可以确保设置了正确的依赖关系,并且在检索到度量值时 Bean 是可用的。如果你发现你在组件或应用程序之间反复测试一套度量标准,那么"),a("code",[e._v("MeterBinder")]),e._v("实现也会很有用。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("默认情况下,来自所有"),a("code",[e._v("MeterBinder")]),e._v("bean 的指标都会自动绑定到 Spring 管理的"),a("code",[e._v("MeterRegistry")]),e._v("。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"_6-5-自定义单个指标"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-5-自定义单个指标"}},[e._v("#")]),e._v(" 6.5.自定义单个指标")]),e._v(" "),a("p",[e._v("如果需要对特定的"),a("code",[e._v("Meter")]),e._v("实例应用自定义,则可以使用"),a("code",[e._v("io.micrometer.core.instrument.config.MeterFilter")]),e._v("接口。")]),e._v(" "),a("p",[e._v("例如,如果你想将"),a("code",[e._v("mytag.region")]),e._v("标记重命名为"),a("code",[e._v("mytag.area")]),e._v(",用于所有以"),a("code",[e._v("com.example")]),e._v("开头的仪表 ID,那么你可以执行以下操作:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('import io.micrometer.core.instrument.config.MeterFilter;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyMetricsFilterConfiguration {\n\n @Bean\n public MeterFilter renameRegionTagMeterFilter() {\n return MeterFilter.renameTag("com.example", "mytag.region", "mytag.area");\n }\n\n}\n\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("默认情况下,所有"),a("code",[e._v("MeterFilter")]),e._v("bean 都自动绑定到 Spring-managed"),a("code",[e._v("MeterRegistry")]),e._v("。"),a("br"),e._v("确保通过使用 Spring-managed 的"),a("code",[e._v("MeterRegistry")]),e._v("来注册你的度量,而不是使用"),a("code",[e._v("Metrics")]),e._v("上的任何静态方法。"),a("br"),e._v("这些方法使用不是 Spring-managed 的全局注册中心。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_6-5-1-公共标签"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-5-1-公共标签"}},[e._v("#")]),e._v(" 6.5.1.公共标签")]),e._v(" "),a("p",[e._v("常见的标记通常用于对操作环境(如主机、实例、区域、堆栈等)进行维度下钻。Commons 标记应用于所有仪表,并且可以进行配置,如下例所示:")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.tags.region=us-east-1\nmanagement.metrics.tags.stack=prod\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('management:\n metrics:\n tags:\n region: "us-east-1"\n stack: "prod"\n')])])]),a("p",[e._v("前面的示例将"),a("code",[e._v("region")]),e._v("和"),a("code",[e._v("stack")]),e._v("标记分别添加到所有值为"),a("code",[e._v("us-east-1")]),e._v("和"),a("code",[e._v("prod")]),e._v("的仪表上。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("如果使用 Graphite,公共标记的顺序很重要。"),a("br"),e._v("由于使用这种方法无法保证公共标记的顺序,建议 Graphite 用户定义一个自定义的"),a("code",[e._v("MeterFilter")]),e._v("。")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"_6-5-2-每米属性"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-5-2-每米属性"}},[e._v("#")]),e._v(" 6.5.2.每米属性")]),e._v(" "),a("p",[e._v("除了"),a("code",[e._v("MeterFilter")]),e._v("bean 之外,你还可以通过使用属性在每米的基础上应用一组有限的定制。每表自定义应用于以给定名称开始的任何表 ID。下面的示例禁用 ID 为的任何仪表。")]),e._v(" "),a("p",[e._v("属性")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management.metrics.enable.example.remote=false\n")])])]),a("p",[e._v("Yaml")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("management:\n metrics:\n enable:\n example:\n remote: false\n")])])]),a("p",[e._v("以下属性允许按米定制:")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th",[e._v("Property")]),e._v(" "),a("th",[e._v("说明")])])]),e._v(" "),a("tbody",[a("tr",[a("td",[a("code",[e._v("management.metrics.enable")])]),e._v(" "),a("td",[e._v("是否防止仪表发出任何度量值.")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("management.metrics.distribution.percentiles-histogram")])]),e._v(" "),a("td",[e._v("是否发布适合于计算可聚集(跨维度)百分位近似的直方图.")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("management.metrics.distribution.minimum-expected-value")]),e._v(", "),a("code",[e._v("management.metrics.distribution.maximum-expected-value")])]),e._v(" "),a("td",[e._v("通过限制期望值的范围,发布更少的直方图桶。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("management.metrics.distribution.percentiles")])]),e._v(" "),a("td",[e._v("发布在应用程序中计算的百分位值")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("management.metrics.distribution.expiry")]),e._v(", "),a("code",[e._v("management.metrics.distribution.buffer-length")])]),e._v(" "),a("td",[e._v("通过在可配置的缓冲区长度"),a("br"),e._v("后旋转的环缓冲区中积累最近的样本,从而赋予它们更大的权重。")])]),e._v(" "),a("tr",[a("td",[a("code",[e._v("management.metrics.distribution.slo")])]),e._v(" "),a("td",[e._v("使用由你的服务级别目标定义的桶发布累积直方图。")])])])]),e._v(" "),a("p",[e._v("有关"),a("code",[e._v("percentiles-histogram")]),e._v("、"),a("code",[e._v("percentiles")]),e._v("和"),a("code",[e._v("slo")]),e._v("背后的概念的更多详细信息,请参见千分尺文档的"),a("a",{attrs:{href:"https://micrometer.io/docs/concepts#_histograms_and_percentiles",target:"_blank",rel:"noopener noreferrer"}},[e._v("“直方图和百分位”部分"),a("OutboundLink")],1),e._v("。")]),e._v(" "),a("h3",{attrs:{id:"_6-6-指标端点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_6-6-指标端点"}},[e._v("#")]),e._v(" 6.6.指标端点")]),e._v(" "),a("p",[e._v("Spring 引导提供了一个"),a("code",[e._v("metrics")]),e._v("端点,你可以诊断地使用该端点来检查应用程序收集的指标。默认情况下端点不可用,必须公开。有关更多详细信息,请参见"),a("code",[e._v("MeterBinder")]),e._v("。")]),e._v(" "),a("p",[e._v("导航到"),a("code",[e._v("/actuator/metrics")]),e._v("将显示可用的仪表名称列表。你可以向下钻取以查看有关特定仪表的信息,方法是将其名称提供为选择器——例如,"),a("code",[e._v("/actuator/metrics/jvm.memory.max")]),e._v("。")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("你在这里使用的名称应该与代码中使用的名称相匹配,而不是与它已被用于所运到的监视系统的命名约定规范化之后的名称相匹配,换句话说, {\n Servlet servlet = new GenericServlet() {\n\n @Override\n public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {\n ServletContext context = req.getServletContext().getContext(contextPath);\n context.getRequestDispatcher("/cloudfoundryapplication").forward(req, res);\n }\n\n };\n context.addServlet("cloudfoundry", servlet).addMapping("/*");\n };\n }\n\n}\n\n')])])]),a("h2",{attrs:{id:"_11-接下来要读什么"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_11-接下来要读什么"}},[e._v("#")]),e._v(" 11. 接下来要读什么?")]),e._v(" "),a("p",[e._v("你可能想了解有关绘图工具的信息,例如"),a("a",{attrs:{href:"https://graphiteapp.org",target:"_blank",rel:"noopener noreferrer"}},[e._v("Graphite"),a("OutboundLink")],1),e._v("。")]),e._v(" "),a("p",[e._v("否则,你可以继续阅读有关"),a("RouterLink",{attrs:{to:"/spring-boot/deployment.html#deployment"}},[e._v("“部署选项”")]),e._v("的内容,或者提前查看有关 Spring boot 的"),a("RouterLink",{attrs:{to:"/spring-boot/build-tool-plugins.html#build-tool-plugins"}},[e._v("构建工具插件")]),e._v("的一些深入信息。")],1)])}),[],!1,null,null,null);t.default=v.exports}}]);