Spring Boot 实现服务器全量信息监控(CPU/JVM/内存/磁盘)

Spring Boot 实现服务器全量信息监控(CPU/JVM/内存/磁盘)

在后端项目开发与运维过程中,服务器的运行状态监控是不可或缺的环节,它能帮助我们及时掌握系统资源使用情况、排查性能瓶颈。本文将基于 oshi 等核心依赖,实现一套完整的服务器信息采集方案,支持 CPU、JVM、内存、磁盘、系统基础信息的精准获取,可直接集成到 Spring Boot 项目中。

一、项目核心依赖(pom.xml)

首先在 pom.xml 中引入所需依赖,核心依赖 oshi-core 用于获取系统硬件和操作系统信息,其他依赖提供 Web 支持、ORM 支持、工具类支持等。

xml 复制代码
<dependencies>
    <!-- 核心:获取服务器硬件/系统信息 -->
    <dependency>
        <groupId>com.github.oshi</groupId>
        <artifactId>oshi-core</artifactId>
        <version>3.9.1</version>
    </dependency>

    <!-- Spring Boot Web 基础依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- MyBatis-Plus 持久层支持(按需引入,非监控核心依赖) -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
    </dependency>

    <!-- Lombok 简化实体类代码 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>

    <!-- MySQL 驱动(按需引入,非监控核心依赖) -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <!-- Apache 工具类 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>

    <!-- 解析客户端操作系统/浏览器(按需引入,非监控核心依赖) -->
    <dependency>
        <groupId>eu.bitwalker</groupId>
        <artifactId>UserAgentUtils</artifactId>
        <version>1.21</version>
    </dependency>

    <!-- JNA 支持(oshi 依赖,用于本地系统调用) -->
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna</artifactId>
        <version>5.7.0</version>
    </dependency>
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna-platform</artifactId>
        <version>5.7.0</version>
    </dependency>
</dependencies>

二、核心实体类设计

实体类用于封装各类服务器监控信息,采用 Lombok @Data 注解简化 getter/setter 编写,部分属性通过自定义 getter 方法实现数据格式化。

1. CPU 信息实体(Cpu.java)

封装 CPU 核心数、总使用率、系统使用率、用户使用率、空闲率等信息。

java 复制代码
package org.monitor.bean;

import lombok.Data;
import org.monitor.util.Arith;

/**
 * CPU相关信息封装
 */
@Data
public class Cpu
{
    /** 核心数 */
    private int cpuNum;

    /** CPU总的使用率 */
    private double total;

    /** CPU系统使用率 */
    private double sys;

    /** CPU用户使用率 */
    private double used;

    /** CPU当前等待率 */
    private double wait;

    /** CPU当前空闲率 */
    private double free;

    public double getTotal()
    {
        // 格式化:乘以100转为百分比,保留2位小数
        return Arith.round(Arith.mul(total, 100), 2);
    }

    public double getSys()
    {
        return Arith.round(Arith.mul(sys / total, 100), 2);
    }

    public double getUsed()
    {
        return Arith.round(Arith.mul(used / total, 100), 2);
    }

    public double getWait()
    {
        return Arith.round(Arith.mul(wait / total, 100), 2);
    }

    public double getFree()
    {
        return Arith.round(Arith.mul(free / total, 100), 2);
    }
}

2. JVM 信息实体(Jvm.java)

封装 JVM 内存使用、版本、启动时间、运行时长等信息。

java 复制代码
package org.monitor.bean;

import java.lang.management.ManagementFactory;
import lombok.Data;
import org.monitor.util.Arith;
import org.monitor.util.DateUtils;

/**
 * JVM相关信息封装
 */
@Data
public class Jvm
{
    /** 当前JVM占用的内存总数(M) */
    private double total;

    /** JVM最大可用内存总数(M) */
    private double max;

    /** JVM空闲内存(M) */
    private double free;

    /** JDK版本 */
    private String version;

    /** JDK路径 */
    private String home;

    public double getTotal()
    {
        // 字节转换为MB,保留2位小数
        return Arith.div(total, (1024 * 1024), 2);
    }

    public double getMax()
    {
        return Arith.div(max, (1024 * 1024), 2);
    }

    public double getFree()
    {
        return Arith.div(free, (1024 * 1024), 2);
    }

    /** 获取JVM已使用内存(M) */
    public double getUsed()
    {
        return Arith.div(total - free, (1024 * 1024), 2);
    }

    /** 获取JVM内存使用率(%) */
    public double getUsage()
    {
        return Arith.mul(Arith.div(total - free, total, 4), 100);
    }

    /** 获取JDK名称 */
    public String getName()
    {
        return ManagementFactory.getRuntimeMXBean().getVmName();
    }

    /** JDK启动时间 */
    public String getStartTime()
    {
        return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate());
    }

    /** JDK运行时间 */
    public String getRunTime()
    {
        return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate());
    }
}

3. 内存信息实体(Mem.java)

封装服务器物理内存的总量、已用、空闲、使用率等信息。

java 复制代码
package org.monitor.bean;

import lombok.Data;
import org.monitor.util.Arith;

/**
 * 物理内存相关信息封装
 */
@Data
public class Mem
{
    /** 内存总量 */
    private double total;

    /** 已用内存 */
    private double used;

    /** 剩余内存 */
    private double free;

    public double getTotal()
    {
        // 字节转换为GB,保留2位小数
        return Arith.div(total, (1024 * 1024 * 1024), 2);
    }

    public void setTotal(long total)
    {
        this.total = total;
    }

    public double getUsed()
    {
        return Arith.div(used, (1024 * 1024 * 1024), 2);
    }

    public void setUsed(long used)
    {
        this.used = used;
    }

    public double getFree()
    {
        return Arith.div(free, (1024 * 1024 * 1024), 2);
    }

    public void setFree(long free)
    {
        this.free = free;
    }

    /** 获取内存使用率(%) */
    public double getUsage()
    {
        return Arith.mul(Arith.div(used, total, 4), 100);
    }
}

4. 系统基础信息实体(Sys.java)

封装服务器名称、IP、项目路径、操作系统名称、系统架构等信息。

java 复制代码
package org.monitor.bean;

import lombok.Data;

/**
 * 服务器系统基础信息封装
 */
@Data
public class Sys
{
    /** 服务器名称 */
    private String computerName;

    /** 服务器Ip */
    private String computerIp;

    /** 项目路径 */
    private String userDir;

    /** 操作系统 */
    private String osName;

    /** 系统架构 */
    private String osArch;
}

5. 磁盘信息实体(SysFile.java)

封装服务器磁盘盘符、类型、总大小、已用大小、空闲大小、使用率等信息。

java 复制代码
package org.monitor.bean;

import lombok.Data;

/**
 * 服务器磁盘文件相关信息封装
 */
@Data
public class SysFile
{
    /** 盘符路径 */
    private String dirName;

    /** 盘符类型 */
    private String sysTypeName;

    /** 文件类型 */
    private String typeName;

    /** 总大小 */
    private String total;

    /** 剩余大小 */
    private String free;

    /** 已经使用量 */
    private String used;

    /** 资源的使用率(%) */
    private double usage;
}

6. 服务器总信息实体(Server.java)

统一封装所有监控信息,提供 copyTo() 方法实现各类信息的采集与赋值。

java 复制代码
package org.monitor.bean;

import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import lombok.Data;
import org.monitor.util.Arith;
import org.monitor.util.IpUtils;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.CentralProcessor.TickType;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

/**
 * 服务器相关信息统一封装
 */
@Data
public class Server
{
    private static final int OSHI_WAIT_SECOND = 1000;

    /** CPU相关信息 */
    private Cpu cpu = new Cpu();

    /** 内存相关信息 */
    private Mem mem = new Mem();

    /** JVM相关信息 */
    private Jvm jvm = new Jvm();

    /** 服务器相关信息 */
    private Sys sys = new Sys();

    /** 磁盘相关信息 */
    private List<SysFile> sysFiles = new LinkedList<SysFile>();

    /**
     * 采集所有服务器监控信息
     */
    public void copyTo() throws Exception
    {
        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();

        setCpuInfo(hal.getProcessor());
        setMemInfo(hal.getMemory());
        setSysInfo();
        setJvmInfo();
        setSysFiles(si.getOperatingSystem());
    }

    /** 设置CPU信息 */
    private void setCpuInfo(CentralProcessor processor)
    {
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(OSHI_WAIT_SECOND);
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;

        cpu.setCpuNum(processor.getLogicalProcessorCount());
        cpu.setTotal(totalCpu);
        cpu.setSys(cSys);
        cpu.setUsed(user);
        cpu.setWait(iowait);
        cpu.setFree(idle);
    }

    /** 设置内存信息 */
    private void setMemInfo(GlobalMemory memory)
    {
        mem.setTotal(memory.getTotal());
        mem.setUsed(memory.getTotal() - memory.getAvailable());
        mem.setFree(memory.getAvailable());
    }

    /** 设置服务器基础信息 */
    private void setSysInfo()
    {
        Properties props = System.getProperties();
        sys.setComputerName(IpUtils.getHostName());
        sys.setComputerIp(IpUtils.getHostIp());
        sys.setOsName(props.getProperty("os.name"));
        sys.setOsArch(props.getProperty("os.arch"));
        sys.setUserDir(props.getProperty("user.dir"));
    }

    /** 设置JVM信息 */
    private void setJvmInfo() throws UnknownHostException
    {
        Properties props = System.getProperties();
        jvm.setTotal(Runtime.getRuntime().totalMemory());
        jvm.setMax(Runtime.getRuntime().maxMemory());
        jvm.setFree(Runtime.getRuntime().freeMemory());
        jvm.setVersion(props.getProperty("java.version"));
        jvm.setHome(props.getProperty("java.home"));
    }

    /** 设置磁盘信息 */
    private void setSysFiles(OperatingSystem os)
    {
        FileSystem fileSystem = os.getFileSystem();
        OSFileStore[] fsArray = fileSystem.getFileStores();
        for (OSFileStore fs : fsArray)
        {
            long free = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            long used = total - free;
            SysFile sysFile = new SysFile();
            sysFile.setDirName(fs.getMount());
            sysFile.setSysTypeName(fs.getType());
            sysFile.setTypeName(fs.getName());
            sysFile.setTotal(convertFileSize(total));
            sysFile.setFree(convertFileSize(free));
            sysFile.setUsed(convertFileSize(used));
            sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100));
            sysFiles.add(sysFile);
        }
    }

    /**
     * 字节大小转换为易读格式(B/KB/MB/GB)
     * @param size 字节大小
     * @return 转换后字符串
     */
    public String convertFileSize(long size)
    {
        long kb = 1024;
        long mb = kb * 1024;
        long gb = mb * 1024;
        if (size >= gb)
        {
            return String.format("%.1f GB", (float) size / gb);
        }
        else if (size >= mb)
        {
            float f = (float) size / mb;
            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
        }
        else if (size >= kb)
        {
            float f = (float) size / kb;
            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
        }
        else
        {
            return String.format("%d B", size);
        }
    }
}

三、核心工具类实现

工具类提供浮点精确运算、时间处理、IP 获取等通用功能,为监控信息采集提供支撑。

1. 浮点精确运算工具类(Arith.java)

解决 double 类型浮点运算精度丢失问题,提供加减乘除、四舍五入等方法。

java 复制代码
package org.monitor.util;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 精确的浮点数运算工具类
 */
public class Arith
{
    /** 默认除法运算精度 */
    private static final int DEF_DIV_SCALE = 10;

    /** 私有构造,禁止实例化 */
    private Arith()
    {
    }

    /** 精确加法运算 */
    public static double add(double v1, double v2)
    {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /** 精确减法运算 */
    public static double sub(double v1, double v2)
    {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /** 精确乘法运算 */
    public static double mul(double v1, double v2)
    {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /** 默认精度除法运算 */
    public static double div(double v1, double v2)
    {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    /** 指定精度除法运算 */
    public static double div(double v1, double v2, int scale)
    {
        if (scale < 0)
        {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        if (b1.compareTo(BigDecimal.ZERO) == 0)
        {
            return BigDecimal.ZERO.doubleValue();
        }
        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
    }

    /** 精确四舍五入处理 */
    public static double round(double v, int scale)
    {
        if (scale < 0)
        {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
    }
}

2. 时间工具类(DateUtils.java)

提供日期格式化、服务器启动时间获取、时间差计算等功能。

java 复制代码
package org.monitor.util;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.lang3.time.DateFormatUtils;

/**
 * 时间工具类(继承Apache DateUtils)
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
{
    public static String YYYY = "yyyy";
    public static String YYYY_MM = "yyyy-MM";
    public static String YYYY_MM_DD = "yyyy-MM-dd";
    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /** 获取当前Date型日期 */
    public static Date getNowDate()
    {
        return new Date();
    }

    /** 获取当前日期(yyyy-MM-dd) */
    public static String getDate()
    {
        return dateTimeNow(YYYY_MM_DD);
    }

    /** 获取当前时间(yyyy-MM-dd HH:mm:ss) */
    public static final String getTime()
    {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    /** 获取当前时间(指定格式) */
    public static final String dateTimeNow(final String format)
    {
        return parseDateToStr(format, new Date());
    }

    /** 日期格式化(指定格式) */
    public static final String parseDateToStr(final String format, final Date date)
    {
        return new SimpleDateFormat(format).format(date);
    }

    /** 字符串转日期(指定格式) */
    public static final Date dateTime(final String format, final String ts)
    {
        try
        {
            return new SimpleDateFormat(format).parse(ts);
        }
        catch (ParseException e)
        {
            throw new RuntimeException(e);
        }
    }

    /** 获取日期路径(年/月/日) */
    public static final String datePath()
    {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /** 获取日期字符串(yyyyMMdd) */
    public static final String dateTime()
    {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /** 字符串转日期(自动匹配格式) */
    public static Date parseDate(Object str)
    {
        if (str == null)
        {
            return null;
        }
        try
        {
            return parseDate(str.toString(), parsePatterns);
        }
        catch (ParseException e)
        {
            return null;
        }
    }

    /** 获取服务器启动时间 */
    public static Date getServerStartDate()
    {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /** 计算相差天数 */
    public static int differentDaysByMillisecond(Date date1, Date date2)
    {
        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
    }

    /** 计算两个时间差(天-时-分) */
    public static String getDatePoor(Date endDate, Date nowDate)
    {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        return day + "天" + hour + "小时" + min + "分钟";
    }
}

3. IP 工具类(IpUtils.java)

提供客户端 IP 获取、服务器 IP/主机名获取、内网 IP 判断等功能。

java 复制代码
package org.monitor.util;

import org.springframework.util.StringUtils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;

/**
 * IP地址工具类
 */
public class IpUtils
{
    /** 获取客户端真实IP */
    public static String getIpAddr(HttpServletRequest request)
    {
        if (request == null)
        {
            return "unknown";
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    /** 判断是否为内网IP */
    public static boolean internalIp(String ip)
    {
        byte[] addr = textToNumericFormatV4(ip);
        return internalIp(addr) || "127.0.0.1".equals(ip);
    }

    /** 判断是否为内网IP(字节数组) */
    private static boolean internalIp(byte[] addr)
    {
        if (StringUtils.isEmpty(addr) || addr.length < 2)
        {
            return true;
        }
        final byte b0 = addr[0];
        final byte b1 = addr[1];
        // 10.x.x.x/8
        final byte SECTION_1 = 0x0A;
        // 172.16.x.x/12
        final byte SECTION_2 = (byte) 0xAC;
        final byte SECTION_3 = (byte) 0x10;
        final byte SECTION_4 = (byte) 0x1F;
        // 192.168.x.x/16
        final byte SECTION_5 = (byte) 0xC0;
        final byte SECTION_6 = (byte) 0xA8;
        switch (b0)
        {
            case SECTION_1:
                return true;
            case SECTION_2:
                if (b1 >= SECTION_3 && b1 <= SECTION_4)
                {
                    return true;
                }
            case SECTION_5:
                switch (b1)
                {
                    case SECTION_6:
                        return true;
                }
            default:
                return false;
        }
    }

    /** 将IPv4地址转换成字节数组 */
    public static byte[] textToNumericFormatV4(String text)
    {
        if (text.length() == 0)
        {
            return null;
        }
        byte[] bytes = new byte[4];
        String[] elements = text.split("\\.", -1);
        try
        {
            long l;
            int i;
            switch (elements.length)
            {
                case 1:
                    l = Long.parseLong(elements[0]);
                    if ((l < 0L) || (l > 4294967295L)) {
                        return null;
                    }
                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 2:
                    l = Integer.parseInt(elements[0]);
                    if ((l < 0L) || (l > 255L)) {
                        return null;
                    }
                    bytes[0] = (byte) (int) (l & 0xFF);
                    l = Integer.parseInt(elements[1]);
                    if ((l < 0L) || (l > 16777215L)) {
                        return null;
                    }
                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 3:
                    for (i = 0; i < 2; ++i)
                    {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L)) {
                            return null;
                        }
                        bytes[i] = (byte) (int) (l & 0xFF);
                    }
                    l = Integer.parseInt(elements[2]);
                    if ((l < 0L) || (l > 65535L)) {
                        return null;
                    }
                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 4:
                    for (i = 0; i < 4; ++i)
                    {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L)) {
                            return null;
                        }
                        bytes[i] = (byte) (int) (l & 0xFF);
                    }
                    break;
                default:
                    return null;
            }
        }
        catch (NumberFormatException e)
        {
            return null;
        }
        return bytes;
    }

    /** 获取服务器IP地址 */
    public static String getHostIp()
    {
        try
        {
            return InetAddress.getLocalHost().getHostAddress();
        }
        catch (UnknownHostException e)
        {
        }
        return "127.0.0.1";
    }

    /** 获取服务器主机名 */
    public static String getHostName()
    {
        try
        {
            return InetAddress.getLocalHost().getHostName();
        }
        catch (UnknownHostException e)
        {
        }
        return "未知";
    }
}

四、测试验证

编写测试类,直接调用 Server 类的 copyTo() 方法,即可采集并输出所有服务器监控信息。

java 复制代码
import org.monitor.bean.Server;

/**
 * 服务器监控信息测试类
 */
public class MonitorTest {
    public static void main(String[] args) throws Exception {
        // 1. 实例化服务器信息对象
        Server server = new Server();
        // 2. 采集所有监控信息
        server.copyTo();
        // 3. 输出监控信息(可根据需求格式化输出或存入数据库)
        System.out.println("服务器CPU信息:" + server.getCpu());
        System.out.println("服务器内存信息:" + server.getMem());
        System.out.println("JVM信息:" + server.getJvm());
        System.out.println("服务器基础信息:" + server.getSys());
        System.out.println("磁盘信息:" + server.getSysFiles());
    }
}

总结

  1. 本方案基于 oshi 核心依赖,实现了 CPU、JVM、物理内存、磁盘、系统基础信息的全量采集,可直接集成到 Spring Boot 项目;
  2. 实体类封装规范,工具类提供精准的数值计算和通用功能,避免了浮点精度丢失、日期处理繁琐等问题;
  3. 测试简单便捷,通过 Server.copyTo() 即可完成所有信息采集,支持后续格式化展示、持久化存储、告警通知等扩展功能。
相关推荐
用户908324602732 天前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
茶杯梦轩2 天前
从零起步学习RabbitMQ || 第二章:RabbitMQ 深入理解概念 Producer、Consumer、Exchange、Queue 与企业实战案例
服务器·后端·消息队列
用户8307196840823 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解3 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解3 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记3 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者4 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840824 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解4 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端
YuMiao4 天前
gstatic连接问题导致Google Gemini / Studio页面乱码或图标缺失问题
服务器·网络协议