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

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

🚀 技术栈

  • Spring Boot

  • OSHI(Operating System and Hardware Information)

  • Java 8+

📦 引入依赖

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

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

📄 控制器代码

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

java 复制代码
@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);
    }
}

🔍 接口示例

访问路径:

java 复制代码
GET /api/system/info

响应示例:

java 复制代码
{
  "项目运行时间": "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、服务器信息、磁盘空间等,非常适合用于服务健康检查、后台管理系统监控页等场景。

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

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

相关推荐
拆房老料6 小时前
【第四部分:Agentic 智能体设计模式】17. Agent 路由模式详解:从意图识别到动态模型选择
java·设计模式·ai编程·策略模式
IT_陈寒6 小时前
Vite开发实战:从入门到精通
前端·人工智能·后端
樱花落木兰6 小时前
Redis 消息队列的可靠性演进:从 List、Pub/Sub 到 Stream 消费者组,以及 8.x 版本改变了什么
java·开发语言·经验分享·redis·分布式·python·软件工程
学长毕设6 小时前
基于SpringBoot的文具商城在线零售系统-附源码
spring boot·后端·零售
wtblszn7 小时前
凹版印刷机智慧运维物联网系统方案
java·运维·物联网
Nuanyt7 小时前
LeetCode Hot 100 链表专题(四)· 3 题(Java)
java·算法·leetcode·链表·双指针
zhongben_keji7 小时前
本地生活 APP 开发:城市 × 品类 × 履约形态的三维网格与三套账
java·大数据·生活
乐橙开放平台7 小时前
离岗检测怎么实现?通过客流相机或 AI 摄像头识别岗位区域无人状态,再推送告警消息
人工智能·笔记·后端·数码相机·物联网·自动化·音视频
code2cat8 小时前
Java工具篇之Maven:从pom.xml到测试通过的JAR
xml·java·maven
wuminyu15 小时前
JVM规范学习总结:解释器与JIT编译器如何处理JVM字节码
java·linux·c语言·jvm·c++