一、了解Actuator
为了在Springboot 应用中启用Actuator,需要在构建文件中添加Actuator starter依赖。在pom.xml添加以下依赖:

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>

添加完成后,应用就具有以下可用Actuator端口:

HTTP方法路径描述默认是否启用
GET/auditevents生成所有已经触发的审计的报告
GET/beans描述Spring应用程序上下文中的所有bean
GET/conditions生成自动配置条件通过或者失败的报告,会指导应用上下文中bean的创建
GET/configprops描述所有配置属性以及当前值
GET, POST, DELETE/env生成Spring应用可用的所有属性源及其属性的报告
GET/env/{toMatch}描述某个环境属性的值
GET/health返回聚合的应用健康状态,可能的话,还会包含外部依赖应用的健康状态
GET/heapdump下载堆dump文件
GET/httptrace生成最近100个请求的跟踪结果
GET/info返回有关开发人员定义的关于该应用的信息
GET/loggers生成应用中源码的包列表,其中会包含配置的以及生效的日志级别
GET, POST/loggers/{name}返回指定logger配置的和生效的日志级别,生效的日志级别可以使用POST请求修改
GET/mappings生成所有HTTP映射及其对应处理器方法的报告
GET/metrics返回所有指标分类的列表
GET/metrics/{name}返回给定指标的多纬度值集
GET/scheduledtasks列出所有的调度任务
GET/threaddump返回所有应用线程的报告

除了基于Http的端点之外,除/headdump的其他端点都以JMX MBean的形式对外暴露。
1、配置Actuator的基础路径
Actuator的前缀可以通过设置management.endpoint.web.base-path属性来修改。
如修改前缀为/management:

management:
  endpoints:
    web:
      base-path: /management

2、启用和禁用Actuator端点
Actuator默认情况下,只有/info和/heath端点是启用的。因为Actuator本身没有保护,所以大多数端点默认是禁用的,需要我们来选择对外暴露哪些端点。
通过这2个属性management.endpoints.web.exposure.include和management.endpoints.web.exposure.exclude。
通过management.endpoints.web.exposure.include属性,可以指定哪些端点想要暴露出来。
如添加以下配置:

management:
 endpoints:
   web:
    exposure:
     include: health,info,beans,conditions

management.endpoints.web.exposure.include可以接受星号(*)作为通配符,表明所有的Actuator端点都会对外暴露,如:

management:
  endpoints:
    web:
     exposure:
        include: '*'

如果除了个别端点之外,想暴露其他的所有端点,可以明确排除一部分,如,想排除"/threaddump"和/heapdump之外的端点。
management.endpoints.web.exposure.include和management.endpoints.web.exposure.exclude属性:

management:
 endpoints:
   web:
     exposure:
       include: '*'
       exclude: threaddump,heapdump

注:还可以结合Spring Security 来限制对其他端点的访问。
二、消费Actuator端点
作为HTTP端点,这些可以像任何REST API一样被消费,选择任意的HTTP客户端,包括Spring的RestTemplate和WebClient,来自基于浏览器的JavaScript应用以及简单地使用curl命令行客户端。
向Actuator发送一个GET请求。借助curl工具:

$ curl http://localhost:8081/actuator

返回:

{
	 "_links": {
	 "self": {
	 	"href": "http://localhost:8081/actuator",
	 	"templated": false
	 },
	 "auditevents": {
		 "href": "http://localhost:8081/actuator/auditevents",
		 "templated": false
	 },
	 "beans": {
		 "href": "http://localhost:8081/actuator/beans",
		 "templated": false
	 },
	 "health": {
		 "href": "http://localhost:8081/actuator/health",
		 "templated": false
	 },
	 // ...
	 }
}

1、获取应用的基础信息

$ curl localhost:8081/actuator/info

返回:

{}

1)请求关于应用的信息
可以在application.yml文件中配置info如下的属性:

info:
 contact:
	 email: myemail@demowebsite.com
	 phone: xxxxxxxx

再次curl请求:

curl http://localhost:8081/actuator/info
{
	 "contact": {
	 "email": "myemail@demowebsite.com",
	 "phone": "xxxxxxxx"
	 }
}

2)查看应用的健康状况

$ curl localhost:8081/actuator/health

返回:

{"status":"UP"}
UP:外部系统是启动并且可以访问
DOWN:外部系统已经停机或者不可访问 
UNKNOWN:外部系统的状态尚不清楚
OUT_OF_SERVICE:外部系统是可访问的,但目前是不可用的

默认情况,只包含聚合的状态。
可以配置management.endpoint.health.show-details属性,展示完整细节,
application.yml:

management:
  endpoint:
    health:
      show-details: always

SpringBoot还为多个外包数据库和系统提供了健康指示器,

Cassandra
Config Server
Couchbase
Eureka
Hystrix
JDBC data sources
Elasticsearch
InfluxDB
JMS message brokers
LDAP
Email servers
Neo4j
Rabbit message brokers
Redis
Solr

2、查看配置细节
1)获取bean的装配报告
/beans端点,返回的JSON文档描述了应用上下文中的每个bean,包括它的java类型以及被注入的其他bean。
如:

$ curl localhost:8081/actuator/beans

2)自动装配
/conditions端点的自动装配分为3部分: positive matches,negative matches,unconditional classes。
如:

$ curl localhost:8081/actuator/conditions

3)查看环境和配置属性
/env应用中发挥作用的属性源
如:

$ curl localhost:8081/actuator/env

还可以获取特定的属性:
如 /env/server.port:

$ curl localhost:8081/actuator/env/server.port

/env 不仅能读取属性的值,还可以向/env端点发送POST请求,如同时提交JSON文档格式的name和value字段,为正在运行的应用设置属性。

$ curl localhost:8081/actuator/env  -d'{"name":"websitedemo.discount.code","value":"demo123123"}'  -H "Content-type: application/json"

响应返回:

{
    "websitedemo.discount.code": "demo123123"
}

再发送请求查看/env:

$ curl localhost:8081/actuator/env

可以看到多了新增的属性。
发送delete请求可以删除属性:

$ curl localhost:8081/actuator/env  -X DELETE {"websitedemo.discount.code": "demo123123"}

再查看/env,返回中已经没有了删除的属性。

4)HTTP映射导览
/mappings端点为应用中所有HTTP请求处理器提供了一个一站式的视图。不管是来自SpringMVC还是Actuator端点。

$ curl localhost:8081/actuator/mappings

5)管理日志级别
/loggers端点 发送get请求

$ curl localhost:8081/actuator/loggers

还可以查看指定包下的日志级别:

$ curl localhost:8081/actuator/loggers/com.example.mywesitedemo

处理返回应用程序中包的日志级别外,通过/loggers端点发送POST请求来修改已配置的日志级别。

$ curl localhost:8081/actuator/loggers/mywesitedemo/ingredients -d'{"configuredLevel":"DEBUG"}'  -H"Content-type: application/json"

3、查看应用的活动
/httptrace, /threaddump,/heapdump端点。
1)跟踪HTTP活动
/httptrace端点

$ curl http://localhost:8081/actuator/httptrace

2)监控线程
/threaddump端点

$ curl http://localhost:8081/actuator/threaddump

4、获取应用的指标
/metrics端点
查看

$ curl http://localhost:8081/actuator/metrics

发送请求到/metrics/http.server.requests

$ curl http://localhost:8081/actuator/metrics/http.server.requests

返回:指标分类详情。
使用availableTags列出标签进一步细化结果。
比如请求HTTP 404的请求有多少:借助status标签

$ curl http://localhost:8081/actuator/metrics/http.server.requests?tag=status:404

又想知道有多少HTTP404响应式发送到/**路径的,通过进一步过滤即可:

$ curl http://localhost:8081/actuator/metrics/http.server.requests?tag=status:404&tag=uri:/**

三、自定义Actuator
1、为/info 端点提供信息
1)创建自定义的InfoContributor

package tacos.tacos;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.actuate.info.Info.Builder;

@Component
public class TacoCountInfoContributor implements InfoContributor {
	private TacoRepository tacoRepo;
	public TacoCountInfoContributor(TacoRepository tacoRepo) {
		this.tacoRepo = tacoRepo;
	}
	
	@Override
	public void contribute(Builder builder) {
		long tacoCount = tacoRepo.count();
		Map<String, Object> tacoMap = new HashMap<String, Object>();
		tacoMap.put("count", tacoCount);
		builder.withDetail("taco-stats", tacoMap);
	}
}

访问:

$ curl http://localhost:8081/actuator/info

返回响应:

{
	"taco-stats": {
	 	"count": 44
	 }
}

2)注入构建信息“/info”端点中

3)暴露Git提交信息

<build>
	 <plugins>
		<!-- ...-->
		 <plugin>
			 <groupId>pl.project13.maven</groupId>
			 <artifactId>git-commit-id-plugin</artifactId>
		 </plugin>
	 </plugins>
</build>

2、实现自定义的健康指示器
创建一个实现了HealthIndicator接口的bean。
如:

package com.example.myhealth ;

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

import java.util.Calendar;

@Component
public class WackoHealthIndicator  implements HealthIndicator {

    @Override
    public Health health() {
        int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        if (hour > 12) {
            return Health
                    .outOfService()
                    .withDetail("reason",
                            "I'm out of service after lunchtime")
                    .withDetail("hour", hour)
                    .build();
        }
        if (Math.random() < 0.1) {
            return Health
                    .down()
                    .withDetail("reason", "I break 10% of the time")
                    .build();
        }
        return Health
                .up()
                .withDetail("reason", "All is good!")
                .build();
    }
}

当对外外部系统发起了一个远程调用,并给予接收到的响应状态进行判断,这样就是一个非常有用的健康指示器了。
3、注册自定义的指标
/metrics端点

package tacos.tacos;
import java.util.List;
import org.springframework.data.rest.core.event.AbstractRepositoryEventListener;
import org.springframework.stereotype.Component;
import io.micrometer.core.instrument.MeterRegistry;

@Component
public class TacoMetrics extends AbstractRepositoryEventListener<Taco> {
	 private MeterRegistry meterRegistry;
	 
	 public TacoMetrics(MeterRegistry meterRegistry) {
	 	this.meterRegistry = meterRegistry;
	 }
	 
	 @Override
	 protected void onAfterCreate(Taco taco) {
		 List<Ingredient> ingredients = taco.getIngredients();
		 for (Ingredient ingredient : ingredients) {
		 	meterRegistry.counter("tacocloud",
		 	"ingredient", ingredient.getId()).increment();
		 }
	 }
}

TacoMetrics 通过构造器注入了MeterRegistry ,扩展了AbstractRepositoryEventListener,这是Spring Data中的一个类,能够拦截repository事件。
这里重写了onAfterCreate方法,保证新的Taco对象保存都会得到通知。
查询/metrics端点来获取计数信息。
4、创建自定义的端点
通过添加@Endpoint注解来实现。
Actuator端点的操作是通过为方法添加@ReadOperation, @WriteOperation和 @DeleteOperation注解实现的。
允许Actuator与各种各样的通信机制协作,内置了对HTTP和JMX的支持。
自定义一个端点如:

package com.example.myendpoint;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Component
@Endpoint(id="notes", enableByDefault=true)
public class NotesEndpoint {
    private List<Note> notes = new ArrayList<>();

    @ReadOperation
    public List<Note> notes() {
        return notes;
    }

    @WriteOperation
    public List<Note> addNote(String text) {
        notes.add(new Note(text));
        return notes;
    }

    @DeleteOperation
    public List<Note> deleteNote(int index) {
        if (index < notes.size()) {
            notes.remove(index);
        }
        return notes;
    }

    @RequiredArgsConstructor
    private class Note {
        @Getter
        private Date time = new Date();
        @Getter
        private final String text;
    }
}

在application.yml添加notes端点:


management:
  endpoints:
    web:
      exposure:
        include: notes

访问:

$ curl  http://localhost:8081/actuator/notes -d'{"text":"Bring home milk"}' -H"Content-type: application/json

返回:

[{"time":"2018-06-08T06:21:01.085+0000","text":"Bring home milk"}]

删除其中一个,发送delete请求。并将index作为请求参数。

$ curl localhost:8081/actuator/notes?index=1 -X DELETE

它们会暴露MBean,可以使用任意的JMX客户端来进行访问。如果只想暴露HTTP端点,可以使用@WebEndpoint注解而不是 @Endpoint来标注端点类。

@Component
@WebEndpoint(id="notes", enableByDefault=true)
public class NotesEndpoint {
 //...
}

四、保护Actuator
可以使用Spring Security来保护Actuator
如,只有ROLE_ADMIN权限的用户才能调用Actuator端点。
重写WebSecurityConfigurerAdapter的configure()方法:

@Override
protected void configure(HttpSecurity http) throws Exception {
	 http
	 .authorizeRequests()
	 	.antMatchers("/actuator/**").hasRole("ADMIN")
	 .and()
	 .httpBasic();
}

这样就只有ROLE_ADMIN权限的授权用户才能访问。现在端点是硬编码“/actuator/**”,如果修改了management.endpoints.web.base-path属性,这种方式就无法正常运行了。
SpringBoot提供了EndpointRequest(一个请求匹配器类,它可以使其更容易且更少地依赖于给定的字符串路径)。
修改上面代码如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
	 http
	 .requestMatcher(EndpointRequest.toAnyEndpoint())
	 	.authorizeRequests()
	 		.anyRequest().hasRole("ADMIN")
	 .and()
	 .httpBasic();
}

EndpointRequest.toAnyEndpoint()返回一个请求匹配器,它会匹配所有的Actuator端点。
如果想要将某些端点从请求匹配中移除,可以调用excluding()方法,通过名称进行声明。
如:

@Override
protected void configure(HttpSecurity http) throws Exception {
	 http
	 .requestMatcher(EndpointRequest.toAnyEndpoint()
	 						.excluding("health", "info"))
	 .authorizeRequests()
	 	.anyRequest().hasRole("ADMIN")
	 .and()
	 	.httpBasic();
}

如果只是想将安全应用到一部分Actuator端点中,可以调用to()来替换toAnyEndpoint()方法,并使用名称指明这些端点,如:

@Override
protected void configure(HttpSecurity http) throws Exception {
	http
		.requestMatcher(EndpointRequest.to(
			"beans", "threaddump", "loggers"))
		.authorizeRequests()
			.anyRequest().hasRole("ADMIN")
		.and()
			.httpBasic();
}

这样只会将安全功能应用到 /beans, /threaddump, 和/loggers 端点上。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐