actuator是Spring Boot项目中非常强大的一个功能,有助于对应用程序进行监控和管理,通过Restful API请求来监管、审计、收集应用的运行情况,针对微服务而言它是必不可少的一个环节。
Endpoints(端点)是actuator的核心部分,它用来监视应用程序及交互,spring-boot-actuator中已经内置了非常多的Endpoints(health、info、beans、httptrace、shutdown)等等,同时也允许我们自己扩展自己的端点
spring boot 2.0中的端点和之前版本有较大不同,使用时需要注意。另外端点的监控机制也有很大不同,启用了不代表可以直接访问,还需要将其暴露出来,传统的management.security管理已被标记为不推荐。
内置Endpoints
id | desc | Sensitive |
---|---|---|
auditevents |
显示当前应用程序的审计事件信息 | Yes |
beans |
显示应用Spring Beans的完整列表 | Yes |
caches |
显示可用缓存信息 | Yes |
conditions |
显示自动装配类的状态及及应用信息 | Yes |
configprops |
显示所有 @ConfigurationProperties 列表 | Yes |
env |
显示 ConfigurableEnvironment 中的属性 | Yes |
flyway |
显示 Flyway 数据库迁移信息 | Yes |
health |
显示应用的健康信息(未认证只显示status ,认证显示全部信息详情) |
No |
info |
显示任意的应用信息(在资源文件写info.xxx即可) | No |
liquibase |
展示Liquibase 数据库迁移 | Yes |
metrics |
展示当前应用的 metrics 信息 | Yes |
mappings |
显示所有 @RequestMapping 路径集列表 | Yes |
scheduledtasks |
显示应用程序中的计划任务 | Yes |
sessions |
允许从Spring会话支持的会话存储中检索和删除用户会话。 | Yes |
shutdown |
允许应用以优雅的方式关闭(默认情况下不启用) | Yes |
threaddump |
执行一个线程dump | Yes |
httptrace |
显示HTTP跟踪信息(默认显示最后100个HTTP请求 - 响应交换) | Yes |
在pom.xml中添加spring-boot-starter-actuator的依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
如果需要访问info接口来获取maven中的属性内容请记得添加如下内容
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<executions>
<execution>
<goals>
<goal>build-infogoal>
goals>
execution>
executions>
plugin>
plugins>
build>
在application.yml文件中配置actuator的相关配置,其中info开头的属性,就是访问info端点中显示的相关内容,值得注意的是spring boot2.x中,默认只开放了info、health两个端点,其余的需要自己通过配置management.endpoints.web.exposure.include属性来加载(有include自然就有exclude)。如果想单独操作某个端点可以使用management.endpoint.端点.enabled属性进行启用或者禁用。
info:
head: head
body: body
management:
endpoints:
web:
exposure:
# 加载所有的端点,默认只加载了info、health
include: '*'
endpoint:
health:
show-details: always
# 可以关闭指定的端点
shutdown:
enabled: false
测试
启动项目,浏览器输入:http://localhost:8080/actuator/info
{"head":"head","body":"body"}
上面很多都是配置相关的,以及自带的一些端点,在实际应用中又时候默认并不能满足我们的需求。
下列是依赖spring-boot-xxx-starter后相关HealthIndicator的实现(通过management.health.defaults.enabled属性可以禁用他们),但想要获取一些额外的信息时,自定义的作用就体现出来了。
name | desc |
---|---|
CassandraHealthIndicator |
检查 Cassandra 数据库是否启动。 |
DiskSpaceHealthIndicator |
检查磁盘空间不足。 |
DataSourceHealthIndicator |
检查是否可以获得连接 DataSource 。 |
ElasticsearchHealthIndicator |
检查 Elasticsearch 集群是否启动。 |
InfluxDbHealthIndicator |
检查 InfluxDB 服务器是否启动。 |
JmsHealthIndicator |
检查 JMS 代理是否启动。 |
MailHealthIndicator |
检查邮件服务器是否启动。 |
MongoHealthIndicator |
检查 Mongo 数据库是否启动。 |
Neo4jHealthIndicator |
检查 Neo4j 服务器是否启动。 |
RabbitHealthIndicator |
检查 Rabbit 服务器是否启动。 |
RedisHealthIndicator |
检查 Redis 服务器是否启动。 |
SolrHealthIndicator |
检查 Solr 服务器是否已启动。 |
实现HealthIndicator接口,根据自己的需要判断返回的状态是UP还是DOWN,功能简单。
package com.spring.boot.health;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component("my1")
public class MyHealthIndicator implements HealthIndicator {
private static final String VERSION = "v1.0.0";
@Override
public Health health() {
int code = 0;
if(code != 0){
Health.down().withDetail("code",code).withDetail("version",VERSION).build();
}
return Health.up().withDetail("code",code)
.withDetail("version",VERSION).up().build();
}
}
输入测试地址:http://localhost:8080/actuator/health
{
"status": "DOWN",
"details": {
"my1": {
"status": "UP",
"details": {
"code": 0,
"version": "v1.0.0"
}
},
"rabbit": {
"status": "DOWN",
"details": {
"error": "org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused (Connection refused)"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 250790436864,
"free": 67546259456,
"threshold": 10485760
}
},
"db": {
"status": "UP",
"details": {
"database": "MySQL",
"hello": 1
}
},
"redis": {
"status": "DOWN",
"details": {
"error": "org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 10.211.55.5:6379"
}
}
}
}
可以看到当前项目的健康程度,由于没有开启linux虚拟机中的redis及rabbitMQ 所以发生异常了,平时启动项目时不去执行是不会报错的
继承AbstractHealthIndicator抽象类,重写doHealthCheck方法,功能比第一种要强大一点,默认的DataSourceHealthIndicator、RedisHealthIndicator都是这种写法,内容回调中还做了异常的处理。
package com.spring.boot.health;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.stereotype.Component;
/**
* 功能更强大,AbstractHealthIndicator实现了HealthIndicator接口
*/
@Component("my2")
public class MyAbstractHealthIndicator extends AbstractHealthIndicator {
private static final String VERSION = "v1.0.1";
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
int code = 0;
if(code != 0){
builder.down().withDetail("code",code).withDetail("version",VERSION).build();
}
builder.withDetail("code",code).withDetail("version",VERSION).up().build();
}
}
测试: http://localhost:8080/actuator/health
{
"status": "DOWN",
"details": {
"my2": {
"status": "UP",
"details": {
"code": 0,
"version": "v1.0.1"
}
},
"my1": {
"status": "UP",
"details": {
"code": 0,
"version": "v1.0.0"
}
},
"rabbit": {
"status": "DOWN",
"details": {
"error": "org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused (Connection refused)"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 250790436864,
"free": 67543334912,
"threshold": 10485760
}
},
"db": {
"status": "UP",
"details": {
"database": "MySQL",
"hello": 1
}
},
"redis": {
"status": "DOWN",
"details": {
"error": "org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 10.211.55.5:6379"
}
}
}
}
info、health都是spring-boot-actuator内置的,真正要实现自己的端点还得通过@Endpoint
、@ReadOperator
、@WriteOperation
、@DeleteOperation
。
不同请求的操作,调用时缺少必须参数,或者使用无法转换为所需类型的参数,则不会调用操作方法,响应状态为400(错误请求)
@Endpoint
: 构建rest api的唯一路径
@ReadOperation
: GET请求,响应状态为200 如果没有返回值响应404(资源未找到)
@WriteOperation
: POST请求,响应状态为200如果没有返回值响应204(无响应内容)
@DeleteOperation
: DELETE请求,响应状态为200如果没有返回值响应204(无响应内容)
package com.spring.boot.endpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import java.util.HashMap;
import java.util.Map;
@Endpoint(id = "jack")
public class MyEndPoint {
@ReadOperation
public Map<String,String> test(){
Map<String,String> result = new HashMap<>();
result.put("name","jack");
result.put("age","20");
return result;
}
}
然后在启动类中注入bean
package com.spring.boot;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.spring.boot.endpoint.MyEndPoint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
@EnableCaching
@SpringBootApplication
public class BootApplication{
public static void main(String[] args) {
SpringApplication.run(BootApplication.class,args);
}
@Configuration
static class MyEndpointConfiguration{
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
public MyEndPoint myEndPoint(){
return new MyEndPoint();
}
}
}
启动项目 输入测试地址:http://localhost:8080/actuator/jack
{"name":"jack","age":"20"}