Spring Boot Actuator-初识篇

关键词:Actuator    JMX


 

Spring Boot Actuator帮助监控和管理正在线上运行的项目。用户可以通过调用提供的HTTP接口或JMX查看项目的一些属性信息,比如健康状况、项目的配置、项目中的Bean等。

Spring Boot官网介绍:《Spring Boot Actuator


█ 使用

(1)引入依赖:

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

(2)配置application.yml

server:
  port: 8080

(3)启动Spring Boot项目

(4)通过HTTP访问接口获取项目信息,请求接口:http:localhost:8080/actuator/

通过访问/autuator接口,可以查看当前暴露出来的endpoint信息。其中的href中的值可以访问对应的endpoint信息,比如:http://localhost:8080/actuator/health获取当前Spring Boot项目环境中的配置信息:

(4)通过Jconsole查看JMX获取项目信息:


█ Endpoints

Spring Boot通过Endpoint提供监控和管理的功能。Spring Boot默认提供了24种EndPoint。

(功能可用和暴露是两个概念,一个EndPoint需要同时满足可用和HTTP暴露或JMX暴露,才能通过HTTP或JMX的方式访问)

EndPoint通过id作为唯一标识,不能重复使用。

id

对应的类

功能描述

默认可用

JMX默认暴露

HTTP默认暴露

health

HealthEndpoint

展示项目的健康信息

info

InfoEndpoint

展示任意应用程序信息

env

EnvironmentEndpoint

暴露ConfigurableEnvironment中的属性

beans

BeansEndpoint

展示应用中所有的Spring Bean

mappings

MappingsEndpoint

展示所有@RequestMapping中的路径

caches

CachesEndpoint

展示可用的缓存

conditions

ConditionsReportEndpoint

展示在配置和自动配置类上评估的条件,以及它们匹配或不匹配的原因。

configprops

ConfigurationPropertiesReportEndpoint

展示所有@ConfigurationProperties标注的配置信息

loggers

LoggersEndpoint

展示和修改应用中的loggers

metrics

MetricsEndpoint

展示当前应用的指标信息

scheduledtasks

ScheduledTasksEndpoint

展示应用中的定时任务

threaddump

ThreadDumpEndpoint

执行一次线程分析

shutdown

ShutdownEndpoint

优雅停机,关闭服务,默认功能不可用

auditevents

AuditEventsEndpoint

暴露当前应用的audit event,需要存在一个类型是AuditEventRepository的bean

需满足条件

需满足条件

flyway

FlywayEndpoint

显示已应用的所有Flyway数据库迁移,需要存在一个或多个Flyway类型的bean

需满足条件

需满足条件

httptrace

HttpTraceEndpoint

HTTP请求链路信息,需要存在一个HttpTraceRepository类型的bean

需满足条件

需满足条件

liquibase

LiquibaseEndpoint

显示已应用的所有Liquibase数据库迁移,需要存在一个或多个Liquibase类型的bean

需满足条件

需满足条件

sessions

SessionsEndpoint

允许从支持会话的Spring会话存储中检索和删除用户会话,需要基于servlet的web应用程序使用Spring Session

需满足条件

需满足条件

integrationgraph

IntegrationGraphEndpoint

显示Spring集成图,需要引入依赖spring-integration-core

需满足条件

需满足条件

startup

 

展示项目启动的时候ApplicationStartup收集的数据,需要SpringApplication配置BufferingApplicationStartup

需满足条件

需满足条件

如果是WEB应用,比如Spring MVC, Spring WebFlux, or Jersey,还提供了如下4个endpoint:

ID

对应的类

功能描述

默认可用

JMX默认可用

HTTP默认可用

heapdump

HeapDumpWebEndpoint

返回一个hprof heap dump 文件

不支持

jolokia

JolokiaEndpoint

通过HTTP公开JMX bean,需要引入依赖jolokia-core

需满足条件

不支持

logfile

LogFileWebEndpoint

返回日志文件的内容

不支持

prometheus

PrometheusScrapeEndpoint

以Prometheus服务器可以获取的格式公开指标,需要引入依赖micrometer-registry-prometheus

需满足条件

不支持

说明:

(1)默认情况下,只有info与health以HTTP接口对外暴露,其他的HTTP服务默认关闭。可通过配置修改开启HTTP服务:

management:
  endpoints:
    web:
      exposure:
        include: beans

(2)配置暴露多个HTTP服务:

management:
  endpoints:
    web:
      exposure:
        include: beans,env

(3)配置暴露所有可用的HTTP服务

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

(4)shutdown功能默认不可用

只有shutdown功能默认是关闭的,可通过配置开启shutdown功能:

management:
  endpoint:
    shutdown:
      enabled: true

(5)更改/actuator访问路径

/actuator是默认的HTTP访问路径,可通过配置更改:

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

(6)management.endpoint.web是设置HTTP接口相关的配置,management.endpoint.jmx是设置JMX相关的配置。

management.endpoints.jmx.exposure.include=beans
management.endpoints.web.exposure.include=beans

(7)条件下功能可用

对于像auditevents这种的EndPoint,当满足条件的情况下才可用。auditevents需要具有AuditEventRepository类型的bean。创建AuditEventRepository类型的bean,Spring Boot提供了一个AuditEventRepository的实现类InMemoryAuditEventRepository:

@Configuration
public class AuditeventsConfiguration {

    @Bean
    public AuditEventRepository auditEventRepository() {
        return new InMemoryAuditEventRepository();
    }

}

█ 自定义Endpoints

Web Endpoints就是支持HTTP方式访问的Endpoints。

JMX Endpoints就是支持JMX方式访问的Endpoints。

  • @EndPoint

使用@EndPoint创建同时支持HTTP与JMX访问的EndPoint。EndPoint通过id作为唯一标识,不能重复使用。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Endpoint {
   // EndPoint的标识,当通过HTTP访问的时候,就是访问路径,比如:beans或health
   String id() default "";
   // 是否可用与暴露,默认为true
   boolean enableByDefault() default true;

}

自定义EndPoint,HTTP访问路径:/actuator/appName:

/**
 * 使用@EndPoint注解自定义EndPoint
 *
 * 会同时支持JMX与HTTP访问
 *
 * @author javaerui
 * @Description:
 * @date 2020/12/10
 */
@Endpoint(id = "appName")
@Component // 使用@Component加入Spring 容器中,使该类能被加载到
public class CustomNameEndPoint {

    @ReadOperation // 可读操作,对应到HTTP的GET请求
    public String getAppName() {
        return "this is my app name";
    }
}
  • @WebEndpoint

使用@WebEndpoint创建只支持HTTP访问的EndPoint。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
// 通过WebEndpointFilter来过滤只支持HTTP访问
@FilteredEndpoint(WebEndpointFilter.class)
public @interface WebEndpoint {

   @AliasFor(annotation = Endpoint.class)
   String id();

   @AliasFor(annotation = Endpoint.class)
   boolean enableByDefault() default true;

}

自定义EndPoint,HTTP访问路径:/actuator/appName-web:

/**
 * 使用@WebEndPoint注解自定义EndPoint
 *
 * 只支持HTTP访问
 *
 * @author javaerui
 * @Description:
 * @date 2020/12/10
 */
@WebEndpoint(id = "appName-web")
@Component
public class CustomNameWebEndPoint {

    @ReadOperation
    public String getAppName() {
        return "this is my web app name";
    }

}
  • @JmxEndpoint

使用@JmxEndpoint创建只支持JMX访问的EndPoint。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(JmxEndpointFilter.class)
public @interface JmxEndpoint {

   @AliasFor(annotation = Endpoint.class)
   String id() default "";
   
   @AliasFor(annotation = Endpoint.class)
   boolean enableByDefault() default true;

}

自定义EndPoint:

/**
 * 使用JmxEndpoint注解自定义EndPoint
 *
 * 只支持JMX访问
 *
 * @author javaerui
 * @Description:
 * @date 2020/12/10
 */
@JmxEndpoint(id = "appName-Jmx")
@Component
public class CustomNameJmxEndPoint {

    @ReadOperation
    public String getAppName() {
        return "this is my jmx app name";
    }

}
  • ControllerEndpoint

将Controller转换成Endpoint,此时只支持Web Endpoints,不支持JMX Endpoints。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(ControllerEndpointFilter.class)
public @interface ControllerEndpoint {

   @AliasFor(annotation = Endpoint.class)
   String id();

   @AliasFor(annotation = Endpoint.class)
   boolean enableByDefault() default true;

}

自定义EndPoint,HTTP访问路径:/actuator/controller/info/name:

@RestController
@ControllerEndpoint(id = "controller")
@RequestMapping("/info")
public class EndPointController {

    @RequestMapping("/name")
    public String getName() {
        return "controller name";
    }

}
  • @ServletEndpoint

将Servlet转换成Endpoint,此时只支持Web Endpoints,不支持JMX Endpoints。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Endpoint
@FilteredEndpoint(ServletEndpointFilter.class)
public @interface ServletEndpoint {

   @AliasFor(annotation = Endpoint.class)
   String id();

   @AliasFor(annotation = Endpoint.class)
   boolean enableByDefault() default true;

}
  • @ReadOperation

在EndPoint类中标记一个方法是可读操作,在Web Endpoints中通过GET请求访问,属性produces配置方法返回内容的media类型:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ReadOperation {

   String[] produces() default {};

}
  • @WriteOperation

在EndPoint类中标记一个方法是可写操作,在Web Endpoints中通过POST请求访问:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WriteOperation {

   String[] produces() default {};

}
  • @DeleteOperation

在EndPoint类中标记一个方法是可删除操作,在Web Endpoints中通过DELETE请求访问:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DeleteOperation {

   String[] produces() default {};

}
  • @EndpointExtension

对某个Endpoint扩展功能。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EndpointExtension {

  // 指定过滤器
   Class<? extends EndpointFilter<?>> filter();

   // 指定要对哪个Endpoint扩展
   Class<?> endpoint() default Void.class;

}

比如,Spring Boot提供的BeansEndpoint只提供了GET读操作,现在扩展一下提供DELETE删除操作:

/**
 *
 * @EndpointExtension的使用,对现有的EndPoint扩展
 *
 * 对Spring Boot提供的BeansEndpoint扩展
 *
 *
 * @author javaerui
 * @Description:
 * @date 2020/12/11
 */
@EndpointExtension(filter = CustomDiscovererEndpointFilter.class, endpoint = BeansEndpoint.class)
@Component
public class CustomExtension {

    @DeleteOperation
    public String deleteBean() {
        return "delete beans in BeansEndpoint";
    }

}
/**
 *
 * 自定义EndpointFilter
 *
 * Spring Boot默认提供的EndpointFilter几个具体实现类的访问权限是default,同包才能使用,故在外面是无法使用的
 *
 * @author javaerui
 * @Description:
 * @date 2020/12/11
 */
public class CustomDiscovererEndpointFilter extends DiscovererEndpointFilter {
    // 要提供无参构造器,Spring根据无参构造器创建对象
    public CustomDiscovererEndpointFilter() {
        super(WebEndpointDiscoverer.class);
    }
}

(1)使用@ReadOperation注解标注的方法,在通过HTTP方式访问的时候,只支持GET请求方式,同理@WriteOperation只支持POST请求方式,@DeleteOperation只支持DELETE请求方式。

(2)HTTP请求时,GET请求会调用@ReadOperation标记的方法,POST请求会调用@WriteOperation标记的方法,DELETE请求会调用@DeleteOperation标记的方法。

@Endpoint(id = "opt")
@Component
public class CustomNameEndPointOfOperation {


    // HTTP get请求访问 /actuator/opt,返回
    @ReadOperation
    public String read() {
        return "read";
    }

    // HTTP post请求访问 /actuator/opt,返回
    @WriteOperation
    public String write() {
        return "write";
    }

    // HTTP delete请求访问 /actuator/opt,返回
    @DeleteOperation
    public String delete() {
        return "delete";
    }

}

(3)@ReadOperation、@WriteOperation、@DeleteOperation标注的方法可以添加参数。

/**
 *
 * 参数
 *
 * @author javaerui
 * @Description:
 * @date 2020/12/10
 */
@Endpoint(id = "param")
@Component
public class CustomNameWebEndPointWithParam {

    @ReadOperation
    public String read(String param) {
        return "read" + param;
    }

    @WriteOperation
    public String write(String param) {
        return "write" + param;
    }

    @DeleteOperation
    public String delete(String param) {
        return "delete" + param;
    }

}

对于@ReadOperation、@DeleteOperation是使用URL传参,即 /actuator/param?param=endpoint

对于@WriteOperation是使用请求体方式传参:

(4)在同一个Endpoint中重复使用@*Operation。

在同一个Endpoint中重复使用同一个@*Operation注解,比如在同一个Endpoint中多次使用@ReadOperation。对于在WEB Endpoint和JMX Endpoint中情况不一样。

WEB Endpoint:

①默认情况下,使用两次@ReadOperation:

@WebEndpoint(id = "multi")
@Component
public class CustomWebEndPointOfMultiOpt {

    @ReadOperation
    public String getName() {
        return "name";
    }

    @ReadOperation
    public String getAge() {
        return "age";
    }


}

启动报错,不允许重复。

②指定不同的@ReadOperation中produces的值:

@ReadOperation(produces = "application/xml")
public String getName() {
    return "name";
}

// 默认为:produces={"application/vnd.spring-boot.actuator.v3+json","application/vnd.spring-boot.actuator.v2+json","application/json"}
@ReadOperation
public String getAge() {
    return "age";
}

启动成功,访问的时候,通过设置请求头:accept的值来区分,accept=application/xml返回name,accept=application/json返回age。

但是如果两个方法设置的produces具有包含关系,即一个是@ReadOperation(produces = "application/json"),一个是@ReadOperation(produces = {"application/xml","application/json"}),启动可以成功,但是访问接口会报错。因为程序分不清具体调用哪个方法。

 

JMX Endpoint:

①默认情况下,使用两次@ReadOperation:

@JmxEndpoint(id = "jmx-multi")
@Component
public class CustomJmxEndPointOfMultiOpt {

    @ReadOperation
    public String getName() {
        return "name";
    }

    @ReadOperation
    public String getAge() {
        return "age";
    }


}

启动成功。

②创建两个同名的方法,同时使用@ReadOperation:

@ReadOperation
public String getAge() {
    return "age";
}

@ReadOperation
public String getAge(String age) {
    return age;
}

启动报错,不允许重复使用。

对于WEB Endpoint和JMX Endpoint,对于重复使用Operation注解的判断条件是不一样的。JMX是根据方法名来判断重复的。详细的判断规则在《初识篇》中说明。


版权声明:本文为weixin_50518271原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。