Spring Boot提供了收集一些系统信息和对系统进行管理的功能,并会把它们以JMX或Http的方式发布出来,用户可以把它们集成到自己的监控系统。需要使用这些功能时需要添加如下依赖。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
Spring Boot把一类监控和管理称为一个Endpoint。打开jconsole可以看到发布在org.springframework.boot.Endpoint
下的Endpoint。也可以通过浏览器访问/actuator
看到通过Http发布的Endpoint。默认情况下绝大部分的Endpoint都会通过JMX发布(shutdown默认不发布),但只有少部分会通过Http发布,所以你通过JMX可以看到发布了很多Endpoint,而通过Http默认将只能看到info
和health。每一个Endpoint都对应有一个唯一的id,常见的Endpoint有如下这些:
@ConditionalXXX
匹配或不匹配的原因@ConfigurationProperties
信息能够发布哪些将依赖于你的Classpath下拥有哪些Endpoint。关于上面这些Endpoint的介绍请参考https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/html/production-ready-endpoints.html。可以通过management.endpoint.endpointId.enabled
指定某个Endpoint是否可用,比如如果需要禁用info
Endpoint,则可以指定management.endpoint.info.enabled=false
。
前面提到几乎所有的Endpoint都会发布到JMX,少数会发布到HTTP,这是由Spring Boot的Endpoint的默认发布策略决定的,可以通过management.endpoints.enabled-by-default
来改变默认发布策略,比如默认发布的都改为不发布,可以指定management.endpoints.enabled-by-default=false
。但是如果你想把默认不发布的Endpoint通过management.endpoints.enabled-by-default=true
指定为发布则是不可行的。基于这种需求得使用更细粒度的控制。Spring Boot分别为JMX和Http发布方式提供了management.endpoints.jmx.exposure
和management.endpoints.web.exposure
,分别包含了include和exclude属性,用于控制需要发布和不发布的Endpoint。假如不想通过JMX方式发布beans和mappings这两个Endpoint,则可以配置management.endpoints.jmx.exposure.exclude=beans,mappings
,而如果希望通过Web方式发布beans和mappings这两个Endpoint,则可以配置management.endpoints.web.exposure.include=beans,mappings
。如果需要发布所有或者禁用所有,则可以使用*
表示。比如需要通过Web方式发布所有的Endpoint,则可以配置management.endpoints.web.exposure.include=*
。management.endpoints.jmx.exposure.include
属性的默认值是*
,而management.endpoints.web.exposure.include
的默认值是info, health
,而exclude默认都是空。所以当你指定了management.endpoints.jmx.exposure.exclude=beans,mappings
时发布的Endpoint将只剩下beans和mappings。exclude和include是可以一起使用的,比如需要通过Web方式发布除beans和mappings以外的所有Endpoint时可以如下配置。
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=beans,mappings
当同时指定了include和exclude时,exclude将拥有更高的优先级,即exclude中包含的内容一定会被排除。
Spring Boot会对所有Endpoint的无参数的读操作的结果进行缓存,可以通过cache.time-to-live
指定某个Endpoint的无参读操作的缓存时间,比如下面的配置指定了beans这个Endpoint的无参读操作的缓存时间是10秒。
management.endpoint.beans.cache.time-to-live=10s
Web方式发布的Endpoint的默认的根路径是/actuator
,每一个是Endpoint会以Endpoint对应的id发布为二级路径,比如beans这个Endpoint的映射路径是/actuator/beans
。可以通过management.endpoints.web.base-path
调整根路径,通过management.endpoints.web.path-mapping.xxx
调整具体某个Endpoint的路径。比如下面的代码就指定了Endpoint的根路径是/actuator1
,loggers Endpoint的路径是loggers1
,所以访问loggers Endpoint的最终路径是/actuator1/loggers1
。
management.endpoints.web.base-path=/actuator1
management.endpoints.web.path-mapping.loggers=loggers1
前面提到了,Spring Boot提供的用于监控的Endpoint会以JMX或Http的方式发布,Http方式发布的都是Rest接口,响应都是JSON,没有界面。如果你提供自己的监控平台,在自己的监控平台需要访问这些监控信息,可能就会遇到浏览器的跨域问题。可以通过management.endpoints.web.cors.allowed-origins
指定允许哪个域进行跨域访问。比如如果我们的Spring Boot应用部署在http://localhost:8081
,监控平台部署在http://localhost:8080
,则以下配置则允许监控平台访问我们Spring Boot应用上发布的Endpoint。
management.endpoints.web.cors.allowed-origins=http://localhost:8080
如果想更精细的控制跨域时只允许某些请求方式,则可以通过management.endpoints.web.cors.allowed-methods
进行指定。
management.endpoints.web.cors.allowed-methods=GET,POST
如果你需要定义自己的Endpoint,可以定义一个标注了@org.springframework.boot.actuate.endpoint.annotation.Endpoint
的Class,然后把它定义为Spring容器中的一个bean。需要通过@Endpoint
的id属性指定一个唯一的id,可以通过@ReadOperation
、@WriteOperation
和@DeleteOperation
标注方法,分别对应GET、POST和DELETE请求。Endpoint的请求路径还是Endpoint的根路径加上具体Endpoint的id,如果如下的Endpoint的默认请求路径将是/actuator/hello
。
@Component
@Endpoint(id="hello")
public class HelloEndpoint {
@ReadOperation
public String hello() {
return "Hello World";
}
}
使用@Endpoint
标注的Endpoint是可以通过JMX和Http方式发布的,如果只期望通过Http发布,可以使用@org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint
,如果只期望通过JMX发布,可以使用@org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpoint
。
可能为了安全需要,你不希望Endpoint随着你的应用一起发布,并可对外访问。可以为Endpoint发布指定一个另外的端口,或者绑定另外一个内网ip。比如下面指定了绑定的端口号是8089,地址是127.0.0.1,即对应的Endpoint只能在本机通过localhost或127.0.0.1访问。
management.server.port=8089
management.server.address=127.0.0.1
如果想禁用通过Http方式发布Endpoint,可以设置management.server.port=-1
。
HealthEndpoint是用来监控应用的健康状态的。其监控是基于org.springframework.boot.actuate.health.HealthIndicator
接口的,由其health()
返回的org.springframework.boot.actuate.health.Health
来反应某个组件的健康状况,Spring Boot已经提供了一些HealthIndicator实现。如果需要实现自己的HealthIndicator,只需要把它定义为一个bean。
@Component
public class HelloHealthIndicator implements HealthIndicator {
@Override
public Health health() {
if (System.currentTimeMillis()%2==0) {
return Health.down().withDetail("error", "详细信息,可以是一个对象").build();
}
return Health.up().build();
}
}
在通过/actuator/health
查看应用的健康状况时默认只会返回一个总的状态,不会展示详细的每个组件的健康状况。可以通过配置management.endpoint.health.show-details=always
返回每个组件的健康状况。
InfoEndpoint用来展示应用的一些信息,它会把容器中所有org.springframework.boot.actuate.info.InfoContributor
类型的bean发布的信息收集起来。Spring Boot提供了一个org.springframework.boot.actuate.info.EnvironmentInfoContributor
实现,它允许我们把需要展示的应用信息以info.*
的形式定义在application.properties文件中。下面的代码中就定义了info信息,包含属性name和app,其中app又是一个对象,包含一个description。访问InfoEndpoint时你会得到这样的信息:{"name":"Spring Boot","app":{"description":"Hello World"}}
。
info.name=Spring Boot
info.app.description=Hello World
如果有需要也可以实现自己的InfoContributor,并把它定义为bean。下面是一个简单的示例,
@Component
public class HelloInfoContributor implements InfoContributor {
@Override
public void contribute(Builder builder) {
Map<String, Object> detailMap = new HashMap<>();
detailMap.put("map.key1", "value1");
detailMap.put("map.key2", "value2");
detailMap.put("map.key1.key1.1", "value");
Map<String, Object> otherMap = new HashMap<>(detailMap);
detailMap.put("map.key1.key1.2", otherMap);
builder
.withDetail("key1", "value1")
.withDetail("key1.key1.1", "value2")
.withDetails(detailMap);
}
}
实现InfoContributor时,如果你需要展示的信息有多层结构,应当把它们包装为一个Map。上面的代码对应的获取info的结果如下:
{
name: "Spring Boot",
app: {
description: "Hello World"
},
key1: "value1",
key1.key1.1: "value2",
map.key2: "value2",
map.key1: "value1",
map.key1.key1.2: {
map.key2: "value2",
map.key1: "value1",
map.key1.key1.1: "value"
},
map.key1.key1.1: "value"
}
https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/html/production-ready-endpoints.html
https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/html/production-ready-monitoring.html
(注:本文是基于Spring Boot 2.0.3所写)