05. Springboot admin集成Actuator(一)

目录

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.mfbz.cn/a/265842.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构入门精讲 | 第十六篇】并查集知识点及考研408、企业面试练习

上一篇中我们进行了散列表的相关练习&#xff0c;在这一篇中我们要学习的是并查集。 目录 概念伪代码选择题填空题编程题7-1 朋友圈R7-1 笛卡尔树R7-2 部落R7-3 秀恩爱分得快 在许多实际应用场景中&#xff0c;我们需要对元素进行分组&#xff0c;并且在这些分组中进行查询和修…

常用Python自动化测试框架有哪些?优缺点对比

随着技术的进步和自动化技术的出现&#xff0c;市面上出现了一些自动化测试框架。只需要进行一些适用性和效率参数的调整&#xff0c;这些自动化测试框架就能够开箱即用&#xff0c;大大节省了测试时间。而且由于这些框架被广泛使用&#xff0c;他们具有很好的健壮性&#xff0…

代码随想录第三十九天(一刷C语言)|零钱兑换完全平方数

创作目的&#xff1a;为了方便自己后续复习重点&#xff0c;以及养成写博客的习惯。 一、零钱兑换 思路&#xff1a;参考carl文档 1、确定dp数组以及下标的含义&#xff1a;凑足总额为j所需钱币的最少个数为dp[j]。 2、确定递推公式&#xff1a;凑足总额为j - coins[i]的最…

先进制造身份治理现状洞察:从手动运维迈向自动化身份治理时代

在新一轮科技革命和产业变革的推动下&#xff0c;制造业正面临绿色化、智能化、服务化和定制化发展趋势。为顺应新技术革命及工业发展模式变化趋势&#xff0c;传统工业化理论需要进行修正和创新。其中&#xff0c;对工业化水平的判断标准从以三次产业比重标准为主回归到工业技…

WEB 3D技术 three.js 通过lil-gui 控制x y z轴数值 操作分组 设置布尔值控制 颜色材质控制

上文 WEB 3D技术 three.js 通过lil-gui管理公共事件中 我们用 lil-gui 处理了一下基础事件和按钮的管理 那么 本文 我们来具体说说它能做的其他事 我们先将基础代码改成这样 import ./style.css import * as THREE from "three"; //引入lil-gui import { GUI } fro…

web逆向经验

一、JS逆向调试流程 如果网页有跳转&#xff0c;必须勾选 preservelog 防止丢包看一下有没有框架 右键查看框架源代码(弹出式登陆界面)登陆尽量使用错误密码 防止跳转查看关键登陆包 分析哪些参数是加密的使用别的浏览器分析哪些参数是固定的值初步猜测加密方法搜索&#xff0…

【Java】从JDK 8迁移到JDK后续版本

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

MySQL 事务的ACID特性

MySQL事务是什么&#xff0c;它就是一组数据库的操作&#xff0c;是访问数据库的程序单元&#xff0c;事务中可能包含一个或者多个 SQL 语句。这些SQL 语句要么都执行、要么都不执行。我们知道&#xff0c;在MySQL 中&#xff0c;有不同的存储引擎&#xff0c;有的存储引擎比如…

凸优化 2:如何判定凸函数?

凸优化 2&#xff1a;如何判定凸函数&#xff1f; 如何判断一个目标函数是凸函数&#xff1f;如果是凸函数&#xff0c;那ta的定义域是凸集合 一个函数求俩次梯度&#xff0c;大于等于0&#xff0c;那这个函数就是一个凸函数在同样条件下&#xff0c;怎么设计为凸函数模型&…

使用 Elasticsearch 检测抄袭 (二)

我在在之前的文章 “使用 Elasticsearch 检测抄袭 &#xff08;一&#xff09;” 介绍了如何检文章抄袭。这个在许多的实际使用中非常有意义。我在 CSDN 上的文章也经常被人引用或者抄袭。有的人甚至也不用指明出处。这对文章的作者来说是很不公平的。文章介绍的内容针对很多的…

【星海出品】Keepalived 使用基础案例 (二)

keepalived 使用 [rootmaster ~]# cat /etc/keepalived/keepalived.conf ! Configuration File for keepalivedglobal_defs { //全局配置notification_email { //定义报警收件人邮件地址acassenfirewall.locfailoverfirewall.locsysadminfirewall.loc}notification_…

ECMAScript基础入门:从语法到应用

在此之前我以及发布过关于JavaScript基础知识点大家也可以参考 大家有关于JavaScript知识点不知道可以去 &#x1f389;博客主页&#xff1a;阿猫的故乡 &#x1f389;系列专栏&#xff1a;JavaScript专题栏 &#x1f389;ajax专栏&#xff1a;ajax知识点 &#x1f389;欢迎关注…

redis常见数据类型

目录 1.基本全局命令 2.数据结构和内部编码 3.单线程架构 1.基本全局命令 Redis有5种数据结构,但它们都是键值对种的值&#xff0c;对于键来说有一些通用的命令。 KEYS 返回所有满足样式(pattern) 的key。支持如下统配样式。 h?llo 匹配 hello, hallo和hxllo h*llo匹配h…

机场信息集成系统系列介绍(6):机场协同决策支持系统ACDM

目录 一、背景介绍 1、机场协同决策支持系统是什么&#xff1f; 2、发展历程 3、机场协同决策参与方 4、相关定义 二、机场协同决策ACDM的建设目标 &#xff08;一&#xff09;机场协同决策支持系统的宏观目标 1、实现运行数据共享和前序航班信息透明化 2、实现地面资源…

Linux常用基本命令(三)

一、显示命令 1. cat 通式&#xff1a;cat 选项 文件名 只能看普通的文本文件 缺点&#xff1a;如果内容过多会显示不全 选项效果-n显示行号包括空行-b跳过空白行编号-s讲所有的连续的多个空行替换为一个空行&#xff08;压缩成一个空行&#xff09;-A显示隐藏字符 三个标准文件…

十四、W5100S/W5500+RP2040之MicroPython开发<MQTTThingSpeak示例>

文章目录 1. 前言2. 平台操作流程3. WIZnet以太网芯片4. 示例讲解以及使用4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 烧录验证 5. 注意事项6. 相关链接 1. 前言 在这个智能硬件和物联网时代&#xff0c;MicroPython和树莓派PICO正以其独特的优势引领着嵌入式开发…

使用PE信息查看工具和Dependency Walker工具排查因为库版本不对导致程序启动报错问题

目录 1、问题说明 2、问题分析思路 3、问题分析过程 3.1、使用Dependency Walker打开软件主程序&#xff0c;查看库与库的依赖关系&#xff0c;查看出问题的库 3.2、使用PE工具查看dll库的时间戳 3.3、解决办法 4、最后 VC常用功能开发汇总&#xff08;专栏文章列表&…

【数据结构】线性表

一.线性表 1.定义&#xff1a; n个同类型数据元素的有限序列&#xff0c;记为 L为表名&#xff0c;i为数据元素在线性表中的位序&#xff0c;n为线性表的表长&#xff0c;n0时称为空表。 2.数据元素之间的关系&#xff1a; 直接前驱和直接后继 3.抽象数据类型线性表的定义…

PADS Layout安全间距检查报错

问题&#xff1a; 在Pads Layout完成layout后&#xff0c;进行工具-验证设计安全间距检查时&#xff0c;差分对BAK_FIXCLK_100M_P / BAK_FIXCLK_100M_N的安全间距检查报错&#xff0c;最小为3.94mil&#xff0c;但是应该大于等于5mil&#xff1b;如下两张图&#xff1a; 检查&…

SpringBoot的配置高级

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…