Spring Boot 使用 OSHI 实现系统运行状态监控接口

news2025/5/15 1:34:06

在实际开发中,我们经常需要获取服务器的运行状态,例如:CPU 使用率、内存使用情况、磁盘状态、JVM 运行信息等,以便于运维监控和性能分析。本文将基于 Spring Boot + OSHI 实现一个系统信息接口,可返回当前服务运行的详细信息。

🚀 技术栈

  • Spring Boot

  • OSHI(Operating System and Hardware Information)

  • Java 8+

📦 引入依赖

在你的 pom.xml 中添加如下依赖(建议使用最新版):

<!-- OSHI 获取系统硬件信息 -->
<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>6.4.4</version>
</dependency>

📄 控制器代码

创建一个 SystemInfoController 类,提供一个 /api/system/info 接口,返回系统、JVM、CPU、内存、磁盘等运行信息。

@RestController
@RequestMapping("/api/system")
public class SystemInfoController {

    private final long startTime = System.currentTimeMillis();

    @GetMapping("info")
    public Map<String, Object> getSystemInfo() {
        Map<String, Object> result = new LinkedHashMap<>();

        // 运行时长
        long uptimeMillis = System.currentTimeMillis() - startTime;
        result.put("项目运行时间", formatDuration(uptimeMillis));

        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();
        OperatingSystem os = si.getOperatingSystem();

        // CPU 信息
        CentralProcessor processor = hal.getProcessor();
        Map<String, Object> cpu = new LinkedHashMap<>();
        int coreCount = processor.getLogicalProcessorCount();
        long[] ticks1 = processor.getSystemCpuLoadTicks();
        try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
        long[] ticks2 = processor.getSystemCpuLoadTicks();

        long user = ticks2[CentralProcessor.TickType.USER.getIndex()] - ticks1[CentralProcessor.TickType.USER.getIndex()];
        long system = ticks2[CentralProcessor.TickType.SYSTEM.getIndex()] - ticks1[CentralProcessor.TickType.SYSTEM.getIndex()];
        long idle = ticks2[CentralProcessor.TickType.IDLE.getIndex()] - ticks1[CentralProcessor.TickType.IDLE.getIndex()];
        long total = Arrays.stream(ticks2).sum() - Arrays.stream(ticks1).sum();

        cpu.put("核心数", coreCount);
        cpu.put("用户使用率", String.format("%.2f%%", user * 100.0 / total));
        cpu.put("系统使用率", String.format("%.2f%%", system * 100.0 / total));
        cpu.put("当前空闲率", String.format("%.2f%%", idle * 100.0 / total));
        result.put("CPU", cpu);

        // 内存信息
        GlobalMemory memory = hal.getMemory();
        Map<String, Object> mem = new LinkedHashMap<>();
        long totalMem = memory.getTotal();
        long available = memory.getAvailable();
        long used = totalMem - available;
        mem.put("总内存", FormatUtil.formatBytes(totalMem));
        mem.put("已用内存", FormatUtil.formatBytes(used));
        mem.put("剩余内存", FormatUtil.formatBytes(available));
        mem.put("使用率", String.format("%.2f%%", used * 100.0 / totalMem));
        result.put("内存", mem);

        // JVM 信息
        RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
        Map<String, Object> jvm = new LinkedHashMap<>();
        jvm.put("JVM名称", runtime.getVmName());
        jvm.put("Java版本", System.getProperty("java.version"));
        jvm.put("启动时间", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(runtime.getStartTime())));
        jvm.put("运行时长", formatDuration(uptimeMillis));
        jvm.put("运行路径", System.getProperty("user.dir"));
        jvm.put("启动类路径", System.getProperty("java.class.path"));
        jvm.put("启动参数", runtime.getInputArguments());
        result.put("JVM", jvm);

        // 服务器信息
        Map<String, Object> server = new LinkedHashMap<>();
        try {
            server.put("服务器名称", InetAddress.getLocalHost().getHostName());
            server.put("服务器IP", InetAddress.getLocalHost().getHostAddress());
        } catch (Exception e) {
            server.put("服务器名称", "未知");
            server.put("服务器IP", "未知");
        }
        server.put("操作系统", os.toString());
        server.put("系统架构", System.getProperty("os.arch"));
        result.put("服务器信息", server);

        // 磁盘信息
        FileSystem fileSystem = os.getFileSystem();
        List<OSFileStore> fileStores = fileSystem.getFileStores();
        List<Map<String, String>> disks = new ArrayList<>();
        for (OSFileStore fs : fileStores) {
            Map<String, String> disk = new LinkedHashMap<>();
            disk.put("盘符路径", fs.getMount());
            disk.put("类型", fs.getType());
            disk.put("总大小", FormatUtil.formatBytes(fs.getTotalSpace()));
            disk.put("可用空间", FormatUtil.formatBytes(fs.getUsableSpace()));
            disks.add(disk);
        }
        result.put("磁盘状态", disks);

        return result;
    }

    // 格式化运行时长
    private String formatDuration(long uptimeMillis) {
        long seconds = uptimeMillis / 1000;
        long days = seconds / (3600 * 24);
        long hours = (seconds % (3600 * 24)) / 3600;
        long minutes = (seconds % 3600) / 60;
        return String.format("%d天%d小时%d分钟", days, hours, minutes);
    }
}

🔍 接口示例

访问路径:

GET /api/system/info

响应示例:

{
  "项目运行时间": "0天1小时23分钟",
  "CPU": {
    "核心数": 8,
    "用户使用率": "3.57%",
    "系统使用率": "1.29%",
    "当前空闲率": "94.31%"
  },
  "内存": {
    "总内存": "16.0 GiB",
    "已用内存": "8.2 GiB",
    "剩余内存": "7.8 GiB",
    "使用率": "51.33%"
  },
  "JVM": {
    "JVM名称": "OpenJDK 64-Bit Server VM",
    "Java版本": "17",
    "启动时间": "2025-05-13 08:00:00",
    "运行时长": "0天2小时10分钟",
    "运行路径": "/app",
    "启动类路径": "...",
    "启动参数": [...]
  },
  "服务器信息": {
    "服务器名称": "server-01",
    "服务器IP": "192.168.1.10",
    "操作系统": "Linux 5.15.0-1051-azure",
    "系统架构": "amd64"
  },
  "磁盘状态": [
    {
      "盘符路径": "/",
      "类型": "ext4",
      "总大小": "100.0 GiB",
      "可用空间": "62.5 GiB"
    }
  ]
}

📌 总结

本文介绍了如何使用 OSHI 在 Spring Boot 项目中快速构建一个系统运行状态接口,包括 CPU、内存、JVM、服务器信息、磁盘空间等,非常适合用于服务健康检查、后台管理系统监控页等场景。

如果你觉得有用,欢迎点赞 👍、收藏 ⭐、评论交流 💬!

如需源码,可在评论区留言获取或私信我~

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

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

相关文章

kotlin-协程(什么是一个协程)

1.什么指一个协程对于线程来说一个thread就是就是指一个线程&#xff0c;thread为什么成为线程呢&#xff1f;因为他实现了对线程的一个抽象管理&#xff0c;可以管理这个线程&#xff0c;启动&#xff0c;可以查看各种信息 那么协程呢&#xff1f; public fun CoroutineScop…

数组和切片的区别

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

WPF内嵌其他进程的窗口

WPF内嵌其他进程窗口的常见方法有 HwndHost SetParent 和 WindowsFormsHost WinForms Panel SetParent 推荐使用自定义HwndHost 两者的对比区别 示例代码 public class MyWndHost : HwndHost {const int WS_CHILD 0x40000000;const int WS_VISIBLE 0x10000000;const i…

CVPR2025 | Prompt-CAM: 让视觉 Transformer 可解释以进行细粒度分析

Prompt-CAM: Making Vision Transformers Interpretable for Fine-Grained Analysis 摘要-Abstract引言-Introduction方法-Approach预备知识-PreliminariesPrompt-CAM: Prompt Class Attention Map特征识别与定位-Trait Identification and Localization变体与扩展-Variants an…

解锁 DevOps 新境界 :使用 Flux 进行 GitOps 现场演示 – 自动化您的 Kubernetes 部署

前言 GitOps 是实现持续部署的云原生方式。它的名字来源于标准且占主导地位的版本控制系统 Git。GitOps 的 Git 在某种程度上类似于 Kubernetes 的 etcd&#xff0c;但更进一步&#xff0c;因为 etcd 本身不保存版本历史记录。毋庸置疑&#xff0c;任何源代码管理服务&#xf…

LLM大模型中的基础数学工具—— 信号处理与傅里叶分析

Q51: 推导傅里叶变换 的 Parseval 定理 傅里叶变换的 Parseval 定理揭示了啥关系&#xff1f; Parseval 定理揭示了傅里叶变换中时域与频域的能量守恒关系&#xff0c;即信号在时域的总能量等于其在频域的总能量。这就好比一个物体无论从哪个角度称重&#xff0c;重量始终不…

橡胶制品行业质检管理的痛点 质检LIMS如何重构橡胶制品质检价值链

橡胶制品广泛应用于汽车、医疗、航空等领域&#xff0c;其性能稳定性直接关联终端产品的安全性。从轮胎耐磨性测试到密封件耐腐蚀性验证&#xff0c;每一项检测数据都是企业参与市场竞争的核心筹码。然而&#xff0c;传统实验室管理模式普遍面临设备调度混乱、检测流程追溯断层…

CAElinux系统详解

CAElinux 系统详解&#xff1a;从系统层面到专业应用 一、CAElinux 的定位与核心目标 CAElinux 是一款专门为 计算机辅助工程&#xff08;CAE&#xff09; 设计的定制化 Linux 发行版&#xff0c;目标用户为从事工程仿真、数值模拟、高性能计算&#xff08;HPC&#xff09;的…

计算机系统----软考中级软件设计师(自用学习笔记)

目录 1、计算机的基本硬件系统 2、CPU的功能 3、运算器的组成 4、控制器 5、计算机的基本单位 6、进制转换问题 7、原码、反码、补码、移码 8、浮点数 9、寻址方式 10、奇偶校验码 11、海明码 12、循环冗余校验码 13、RISC和CISC 14、指令的处理方式 15、存储器…

django的权限角色管理(RBAC)

在 Django 中&#xff0c;User、Group 和 Permission 是权限系统的核心组件。下面通过代码示例演示它们的 CRUD&#xff08;创建、读取、更新、删除&#xff09; 操作&#xff1a; 一、User 模型 CRUD from django.contrib.auth.models import User# 创建用户 user User.obje…

线性表-顺序表(Sequential List)

1 线性表 1.1 顺序表&#xff08;Sequential List&#xff09; 顺序表并不难理解&#xff0c;主要是知道顺序表是在内存中连续存储的一段数据&#xff0c;知道这个后&#xff0c;相应的算法也就非常简单了。 线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的…

【阿里云免费领取域名以及ssl证书,通过Nginx反向代理web服务】

文章目录 前言一、申请域名1.1 访问阿里云官网1.2 输入自定义域名1.3 创建个人模板1.4 支付1元可以使用域名1年1.5 按照提示实名认证1.6 实名认证成功 二、域名解析2.1 选择域名解析2.2 解析设置2.3 快速添加解析2.4 选择对应类型2.5 解析成功 三、申请免费ssl证书3.1 访问阿里…

数据分析2

五、文件 CSV Comma-Separated Value&#xff0c;逗号分割值。CSV文件以纯文本形式存储表格数据&#xff08;数字和文本&#xff09;。 CSV记录间以某种换行符分隔&#xff0c;每条记录由字段组成&#xff0c;字段间以其他字符或字符串分割&#xff0c;最常用逗号或制表符。…

实战项目5(08)

目录 任务场景一 【r1配置】 【r2配置】 【r3配置】 ​​​​​​​任务场景二 【r1配置】 【r2配置】 ​​​​​​​任务场景一 按照下图完成网络拓扑搭建和配置 任务要求&#xff1a; 通过在路由器R1、R2和R3上配置静态路由&#xff0c;实现网络中各终端PC能够正常…

.NET MAUI 基础知识

文章目录 什么是 .NET MAUI&#xff1f;MAUI的核心特点与Xamarin.Forms的区别 开发环境搭建安装Visual Studio 2022安装必要组件配置Android开发环境配置iOS开发环境验证安装 创建第一个MAUI应用创建新项目MAUI项目结构解析理解关键文件运行应用程序简单修改示例使用热重载 MAU…

佰力博科技与您探讨表面电阻的测试方法及应用领域

表面电阻测试是一种用于测量材料表面电阻值的技术&#xff0c;广泛应用于评估材料的导电性能、静电防护性能以及绝缘性能。 1、表面电阻的测试测试方法&#xff1a; 表面电阻测试通常采用平行电极法、同心圆电极法和四探针法等方法进行。其中&#xff0c;平行电极法通过在试样…

鹅厂面试数学题

题目 一个圆上随机取三个点&#xff0c;求这三个点构成锐角三角形的概率。 解答 根据圆周角定理&#xff0c;此题目等价为&#xff1a;一条线段长度为1的线段随机取两个点分成三段&#xff0c;任意一段长度均不大于1/2的概率。记前两段的长度为&#xff0c;则第三段的长度为…

java基础-package关键字、MVC、import关键字

1.package关键字&#xff1a; &#xff08;1&#xff09;为了更好管理类&#xff0c;提供包的概念 &#xff08;2&#xff09;声明类或接口所属的包&#xff0c;声明在源文件首行 &#xff08;3&#xff09;包&#xff0c;属于标识符&#xff0c;用小写字母表示 &#xff0…

[6-2] 定时器定时中断定时器外部时钟 江协科技学习笔记(41个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 V 30 31 32 33 34 35 36 37 38 39 40 41

【PmHub后端篇】PmHub中基于自定义注解和AOP的服务接口鉴权与内部认证实现

1 引言 在现代软件开发中&#xff0c;尤其是在微服务架构下&#xff0c;服务接口的鉴权和内部认证是保障系统安全的重要环节。本文将详细介绍PmHub中如何利用自定义注解和AOP&#xff08;面向切面编程&#xff09;实现服务接口的鉴权和内部认证&#xff0c;所涉及的技术知识点…