05. Springboot admin集成Actuator(一)

news2025/1/18 20:32:15

目录

1、前言

2、Actuator监控端点

2.1、健康检查

2.2、信息端点

2.3、环境信息

2.4、度量指标

2.5、日志文件查看

2.6、追踪信息

2.7、Beans信息

2.8、Mappings信息

3、快速使用

2.1、添加依赖

2.2、添加配置文件

2.3、启动程序

4、自定义端点Endpoint

5、自定义health

6、附录

7、小结


1、前言

Spring Boot Actuator是Spring Boot提供的一个用于监控和管理应用程序的扩展模块。Actuator通过HTTP端点和JMX(Java Management Extensions)提供了一系列功能,包括查看应用程序的运行状况、度量指标、日志、追踪和应用信息。它为开发人员和运维人员提供了方便的手段来监控和管理Spring Boot应用。

2、Actuator监控端点

Actuator提供了一系列内置的端点(EndPoints)用于查看应用程序的运行状况、运行情况、指标等信息。其中主要提供了如下一些端点:

2.1、健康检查

HTTP端点:`/actuator/health`。提供了应用程序的健康状态,包括磁盘空间、数据库连接等信息。健康检查对于监控和负载均衡非常有用。返回的状态包括 UP(正常)、DOWN(异常)和 OUT_OF_SERVICE(维护中)等。

2.2、信息端点

HTTP端点:`/actuator/info`。提供了应用程序的自定义信息,可以在配置文件中定义,用于展示应用的版本、描述等。这些信息通常来源于应用程序的配置文件或构建系统。

2.3、环境信息

HTTP端点:`/actuator/env`。显示应用程序的环境属性,包括配置属性、系统属性等。可以通过添加参数来查看特定属性的值,如:/actuator/env/server.port。

2.4、度量指标

HTTP端点:`/actuator/metrics`。提供了应用程序的度量指标,例如内存使用、线程池状态、HTTP请求等,对性能分析和优化非常有帮助。如:/actuator/metrics/jvm.memory.used。

2.5、日志文件查看

HTTP端点:`/actuator/logfile`。允许查看应用程序的日志文件内容,方便进行故障排除。

2.6、追踪信息

HTTP端点:`/actuator/trace`。提供了应用程序的请求追踪信息,显示HTTP请求的调用链,便于跟踪请求的处理过程。

2.7、Beans信息

HTTP端点:`/actuator/beans`。显示所有在Spring应用程序上下文中注册的Beans信息,包括它们的名称、类型等。

2.8、Mappings信息

HTTP端点:`/actuator/mappings`。 显示所有的URI映射,展示了请求如何被映射到控制器方法上。

3、快速使用

了解了Actuator的各个主要端点以及他们的作用后,我们便可以选择适当的端点作为我们的监控行为,集成到项目中。

基础环境:SpringBoot-2.7.14,JDK-17.0.2。构建基础springboot demo工程。

3.1、添加依赖

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

3.2、添加配置文件

spring:
  application:
    name: springboot-actuator-demo
server:
  port: 8080


management:
  server:
    port: 8081   # 指定了actuator服务端口
  endpoints:
    web:
      exposure:
        include: '*'    # 表示开启所有端点,如果指定具体多个端点,可以用,隔开。如health,info

3.3、启动程序

启动日志中可以看到启动了actuator端口为8081,且访问路径为/actuator。我们访问下http://localhost:8081/actuator:

可以看到actuator返回了一列指标的访问连接。

接着继续访问给定的连接,实际上就是http://localhost:8081/actuator/端点url。如查看当前JVM内存占用情况,直接访问http://localhost:8081/actuator/metrics/jvm.memory.used

4、自定义端点Endpoint

除了Actuator自带的端点以外,我们还可以自定义所需要的端点。自定义端点需要先了解以下几个注解:

  • @Component:注册为一个Spring Bean。
  • @Endpoint:声明端点的注解,需要指定id=""属性,标识端点名称。
  • @ReadOperation:用于定义读操作,允许获取关于应用程序状态的信息。它对应 HTTP 请求的 GET 方法。通常用于返回只读信息,例如获取应用程序的状态、性能指标等。
  • @WriteOperation:用于定义写操作,允许进行应用程序的修改。它对应 HTTP 请求的 POST 方法。通常用于执行会修改应用程序状态的操作,例如重新加载配置、清理缓存等。
  • @DeleteOperation:用于定义删除操作,允许进行资源的删除。它对应 HTTP 请求的 DELETE 方法。通常用于执行删除资源的操作,例如关闭数据库连接池、停止某个服务等。
  • @Selector:用于@ReadOperation、@WriteOperation、@DeleteOperation标注的 Endpoint 方法时允许传递一些参数。

简单demo:

package com.example.springbootactuator.entpoint;

import org.springframework.boot.actuate.endpoint.annotation.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 注意:这里定义的端点名称只能是英文字母+数字,不能有其他字符,甚至下划线也不行。不然会提示 Value must only contain valid chars
 */
@Component
@Endpoint(id = "myendpoint", enableByDefault = true)
public class MyEndpoint {
    @ReadOperation
    public Map<String, Object> endpointMyRead(@Selector String content) {
        Map<String, Object> customMap = new HashMap<>();
        customMap.put("httpMethod", HttpMethod.GET.toString());
        customMap.put("status", "200");
        customMap.put("content", content);
        return customMap;
    }

    @WriteOperation
    public Map<String, Object> endpointMyWrite() {
        Map<String, Object> customMap = new HashMap<>();
        customMap.put("httpMethod", HttpMethod.POST.toString());
        return customMap;
    }

    @DeleteOperation
    public Map<String, Object> endpointMyDelete() {
        Map<String, Object> customMap = new HashMap<>();
        customMap.put("httpMethod", HttpMethod.DELETE.toString());
        return customMap;
    }
}

运行后查看端点,可以看到多了我们自定义的myendpoint端点名称,同时多了一个可以接收{content}的端点连接,这个就是我们加了@Selector注解,允许接收参数。

来尝试访问下:http://localhost:8081/actuator/myendpoint/hello123123123。可以得到我们返回的map结构。

5、自定义health

我们还可以自定义health,用来检测其健康状态。这个也是我项目中用的比较多的,当时有一个需求是汇总所有的API请求,检测对方的API健康状态,并告警提醒,就是自定义了health。

要自定义health,可以自定义 HealthIndicator 来添加自定义的健康检查项。HealthIndicator 接口定义了一个 health() 方法,该方法返回一个 Health 对象,其中包含了应用程序的健康信息。也可以通过继承AbstractHealthIndicator抽象类来实现。

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

@Component
public class CustomHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        // 实现自定义的健康检查逻辑
        boolean isHealthy = checkHealth(); // 替换为实际的健康检查逻辑

        if (isHealthy) {
            return Health.up()
                    .withDetail("message", "Application is healthy")
                    .build();
        } else {
            return Health.down()
                    .withDetail("message", "Application is not healthy")
                    .build();
        }
    }

    private boolean checkHealth() {
        // 实际的健康检查逻辑,例如检查数据库连接、第三方服务状态等
        // 返回 true 表示健康,返回 false 表示不健康
        // 这里简单返回 true,实际应用中需要根据业务逻辑进行判断
        return true;
    }
}

运行程序,访问http://localhost:8081/actuator/health:

此外,可以添加以下配置,来查看health的详细信息:

management:
   endpoint:
      health:
        show-details: always

6、附录

贴出之前我对第三方API地址进行拨测的,实现health方式来检测健康状态的部分关键代码:

ThirdPartApiManager.java

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;


/**
 * 第三方api地址管理器,统一管理API地址,不要直接在业务代码写死
 * 这里管理的api地址会进行状态监控
 */
@Configuration
public class ThirdPartApiManager {

    @Autowired
    ThirdPartApiIpConfig thirdPartApiIpConfig;

    public static final Table<String, String, Long> THIRD_PART_API_TABLE = HashBasedTable.create();

    /**
     * 每次api心跳间隔,默认10分钟
     */
    public static final Long INTERVAL_MICO_SECONDS = 10 * 60L * 1000;


    @SuppressWarnings("java:S125")
    public void thirdPartApiAdd() {
        //THIRD_PART_API_TABLE.put("获取客户信息", "http://localhost:8080/xxxxx",  1 * 60L * 1000);
    }

}

ThirdPartApiManagerMonitor.java:

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * 第三方api地址心跳拨测
 * 拨测方式:对http发起options预请求,来诊断该接口的可用性
 * 注意:这里不发送trace方法,原因是trace可能会被黑客攻击,所以大多数系统trace是关闭的。
 */
@Component
@Configuration
@AutoConfigureBefore({HealthIndicatorAutoConfiguration.class})
@EnableConfigurationProperties(HealthEndpointProperties.class)
@Slf4j
@Profile({"prod"})
public class ThirdPartApiManagerMonitor implements SchedulingConfigurer {
    @Autowired
    ConfigurableApplicationContext context;

    @Autowired
    ThirdPartApiManager thirdPartApiManager;

    @Bean
    public Map<String, Health> apiHealthResultMap() {
        return new ConcurrentHashMap<>(ThirdPartApiManager.THIRD_PART_API_TABLE.columnKeySet().size());
    }

    Function<ThirdPartApiDto, Health> healthIndicatorFunction = apiDto -> {
        Health.Builder healthBuilder = new Health.Builder()
                .status(String.valueOf(apiDto.getStatus()))
                .withDetail("httpCode", apiDto.getStatus())
                .withDetail("name", apiDto.getName())
                .withDetail("url", apiDto.getApi())
                .withDetail("description", apiDto.getName());

        /**
         * 状态码说明:
         * 100-199 用于指定客户端应相应的某些动作。
         * 200-299 用于表示请求成功。
         * 300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。
         * 400-499 用于指出客户端的错误。
         * 500-599 用于支持服务器错误。
         */
        if (apiDto.getStatus() >= 400) {
            // 推送提醒......
            sendLarkMessage(apiDto);
            return healthBuilder.down().build();
        }
        return healthBuilder.up().build();
    };


    public int tryConnect(String url) {
        try {
            URL urlObj = new URL(url);
            HttpURLConnection connect = (HttpURLConnection) urlObj.openConnection();
            connect.setUseCaches(false);
            connect.setRequestMethod("OPTIONS");
            connect.setConnectTimeout(5000);
            return connect.getResponseCode();
        } catch (IOException e) {
            // nop
            return 500;
        }
    }


    @PostConstruct
    public void registerApiHealth() {
        thirdPartApiManager.thirdPartApiAdd();
        ThirdPartApiManager.THIRD_PART_API_TABLE.columnKeySet().forEach(api -> {
            Optional<String> first = ThirdPartApiManager.THIRD_PART_API_TABLE.column(api).keySet().stream().findFirst();
            if (!first.isPresent()) {
                return;
            }
            context.getBeanFactory().registerSingleton(first.get() + "HealthIndicator", (HealthIndicator) () -> {
                if (apiHealthResultMap().containsKey(first.get())) {
                    return apiHealthResultMap().get(first.get());
                }
                int status = tryConnect(api);
                ThirdPartApiDto thirdPartApiDto = ThirdPartApiDto.builder()
                        .name(first.get())
                        .api(api).interval(ThirdPartApiManager.THIRD_PART_API_TABLE.column(api).getOrDefault(first.get(), ThirdPartApiManager.INTERVAL_MICO_SECONDS))
                        .status(status).result(JSONUtil.toJsonStr(status)).createTime(DateUtil.now()).build();
                return healthIndicatorFunction.apply(thirdPartApiDto);
            });
        });
    }


    /**
     * 按照配置api,定时监控外部http状态
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        ThirdPartApiManager.THIRD_PART_API_TABLE.columnKeySet().forEach(api -> {
            Optional<String> first = ThirdPartApiManager.THIRD_PART_API_TABLE.column(api).keySet().stream().findFirst();
            if (!first.isPresent()) {
                return;
            }
            LOGGER.info("拨测接口:{}, 地址:{}", first.get(), api);
            scheduledTaskRegistrar.addFixedRateTask(() -> {
                int status = tryConnect(api);
                ThirdPartApiDto thirdPartApiDto = ThirdPartApiDto.builder()
                        .name(first.get())
                        .api(api).interval(ThirdPartApiManager.THIRD_PART_API_TABLE.column(api).getOrDefault(first.get(), ThirdPartApiManager.INTERVAL_MICO_SECONDS))
                        .status(status).result(JSONUtil.toJsonStr(status)).createTime(DateUtil.now()).build();
                apiHealthResultMap().put(first.get(), healthIndicatorFunction.apply(thirdPartApiDto));
            }, ThirdPartApiManager.THIRD_PART_API_TABLE.column(api).getOrDefault(first.get(), ThirdPartApiManager.INTERVAL_MICO_SECONDS));
        });
    }

    @Bean
    public HealthIndicator testHealthIndicator() {
        return () -> new Health.Builder().up().build();
    }

    public void sendLarkMessage(ThirdPartApiDto thirdPartApiDto) {
        // ...
    }
}

7、小结

Spring Actuator在实际项目中使用还是很广泛的,根据项目实际情况适当扩展或自定义各个端点,提供更契合场景的度量指标,对项目会有很大的帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1331149.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于epoll的web服务器(C语言版本)

基于epoll的web服务器(C语言版本) 1. 初始化监听套接字 包括创建监听套接字&#xff0c;设置端口复用&#xff0c;绑定&#xff0c;设置监听等步骤 1.1 创建监听套接字&#xff08;socket函数&#xff09; socket()打开一个网络通讯端口&#xff0c;如果成功的话&#xff0…

界面控件DevExpress v23.2全新发布 - 官宣正式支持.NET 8

DevExpress拥有.NET开发需要的所有平台控件&#xff0c;包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具。屡获大奖的软件开发平台DevExpress 今年第一个重要版本v23.1正式发布&#xff0c;该版本拥有众多…

【精选】vulnhub CTF6 linux udev提权 (青铜门笔记)

一、信息收集 1.主机探测 发现靶机的IP地址是&#xff1a;192.168.103.130 ┌──(root&#x1f480;kali)-[~] └─# arp-scan -l2.访问web页面 发现有个登录的页面&#xff0c;尝试了弱口令&#xff0c;但是发现没有成功&#xff1b; 所以&#xff0c;我们需要在后面的信…

单词接龙[中等]

一、题目 字典wordList中从单词beginWord和endWord的 转换序列 是一个按下述规格形成的序列beginWord -> s1 -> s2 -> ... -> sk&#xff1a; 1、每一对相邻的单词只差一个字母。 2、对于1 < i < k时&#xff0c;每个si都在wordList中。注意&#xff0c;beg…

数值分析期末复习

第一章 科学计算 误差 解题步骤 先求绝对误差: ∣ x − x ∗ ∣ |x - x^*| ∣x−x∗∣求相对误差限: ∣ x − x ∗ ∣ x ∗ \frac{|x\,\,-\,\,x^*|}{x^*} x∗∣x−x∗∣​求有效数字 ∣ x − x ∗ ∣ 需要小于它自身的半个单位 |x-x^*|\text{需要小于它自身的半个单位} ∣…

Kafka集群架构原理(待完善)

kafka在zookeeper数据结构 controller选举 客户端同时往zookeeper写入, 第一个写入成功(临时节点), 成为leader, 当leader挂掉, 临时节点被移除, 监听机制监听下线,重新竞争leader, 客户端也能监听最新leader leader partition自平衡 leader不均匀时, 造成某个节点压力过大, …

数字信号的理解

1 数字信号处理简介 数字信号处理 digital signal processing&#xff08;DSP&#xff09;经常与实际的数字系统相混淆。这两个术语都暗示了不同的概念。数字信号处理在本质上比实际的数字系统稍微抽象一些。数字系统是涉及的硬件、二进制代码或数字域。这两个术语之间的普遍混…

物联网产品设计,聊聊设备OTA的升级

物联网产品设计部分的OTA设备固件是一个非常重要的部分&#xff0c;能够实现升级用户服务、保障系统安全等功能。 在迅速变化和发展的物联网市场&#xff0c;新的产品需求不断涌现&#xff0c;因此对于智能硬件设备的更新需求就变得空前高涨&#xff0c;设备不再像传统设备一样…

SQL分类

SQL分类 DDL 查询库 查询表 创建表 修改表 DML 添加数据 修改数据 删除数据 DQL 基本查询 条件查询 聚合函数 分组查询 排序查询 分页查询 执行顺序 DCL 管理用户 管理权限 数据类型 数值类型 字符串类型 日期类型

从零构建tomcat环境

一、官网构建 1.1 下载 一般来说对于开源软件都有自己的官方网站&#xff0c;并且会附上使用文档以及一些特性和二次构建的方法&#xff0c;那么我们首先的话需要从官网或者tomcat上下载到我们需要的源码包。下载地址&#xff1a;官网、Github。 这里需要声明一下&#xff…

龙芯loongarch64服务器编译安装tensorflow-io-gcs-filesystem

前言 安装TensorFlow的时候,会出现有些包找不到的情况,直接使用pip命令也无法安装,比如tensorflow-io-gcs-filesystem,安装的时候就会报错: 这个包需要自行编译,官方介绍有限,这里我讲解下 编译 准备 拉取源码:https://github.com/tensorflow/io.git 文章中…

80x86汇编—汇编程序基本框架

文章目录 First Program指令系统伪指令数值表达式 程序框架解释int 21 中断 通过一个基本框架解释各个指令和用处&#xff0c;方便复习。所以我认为最好的学习顺序就是先看一段完整的汇编代码程序&#xff0c;然后给你逐个逐个的解释每一个代码是干嘛用的。然后剩下的还有很多指…

linux的主线程提前子线程退出以及线程分离

主线程提前退出 如果主线程没有等待子线程提前退出&#xff0c;可能会发生以下情况&#xff1a; 子线程继续运行&#xff1a;如果主线程退出&#xff0c;但子线程仍在执行任务&#xff0c;子线程将继续独立运行。子线程的生命周期不受主线程控制&#xff0c;直到子线程自行完成…

Latex生成的PDF中加入书签/Navigation/导航

本文参考&#xff1a;【Latex学习】在生成pdf中加入书签/目录/提纲_latex 书签-CSDN博客 &#xff08;这篇文章写的真的太棒了&#xff01;非常推荐&#xff09; 题外话&#xff0c;我的碎碎念&#xff0c;这也是我如何提高搜索能力的办法&#xff1a;想在Latex生成的PDF中加入…

python脚本 链接到ssh服务器 快速登录ssh服务器 ssh登录

此文分享一个python脚本,用于管理和快速链接到ssh服务器。 效果演示 🔥完整演示效果 👇第一步,显然,我们需要选择功能 👇第二步,确认 or 选择ssh服务器,根据配置文件中提供的ssh信息,有以下情况 👇场景一,只有一个候选ssh服务器,则脚本会提示用户是否确认链…

【hcie-cloud】【9】华为云Stack_Deploy部署工具介绍

文章目录 前言华为云Stack Deploy简介华为云Stack Deploy工具简介华为云Stack Deploy工具部署范围华为云Stack Deploy工具节点网络要求华为云Stack Deploy工具部署流程 华为云Stack Deploy功能介绍部署工具工程场景部署流程介绍创建工程 - 基本信息填写创建工程 - 基本参数选择…

【ITK库学习】使用itk库进行图像配准:“Hello World”配准

目录 1、itkImageRegistrationMethod / itkImageRegistrationMethodv42、itkTranslationTransform3、itkMeanSquaresImageToImageMetric / itkMeanSquaresImageToImageMetric44、itkRegularStepGradientDescentOptimizerv / itkRegularStepGradientDescentOptimizerv4 图像配准…

0基础学习VR全景平台篇第130篇:曝光三要素—感光度

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 众所周知&#xff0c;摄影是一门用光的艺术。随着天气、地点、时间的变化&#xff0c;我们所处环境的光线也随之发生改变。而在不同的环境下该如何去正确的调节曝光&#xff0c;是…

Spring security之授权

前言 本篇为大家带来Spring security的授权&#xff0c;首先要理解一些概念&#xff0c;有关于&#xff1a;权限、角色、安全上下文、访问控制表达式、方法级安全性、访问决策管理器 一.授权的基本介绍 Spring Security 中的授权分为两种类型&#xff1a; 基于角色的授权&…

【Angular】Angular中的最差实践

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…