可爱静

记录生活、学习和工作

0%

SpringBoot获取系统信息

添加依赖

  1. JNA(Java Native Access )提供一组Java工具类用于在运行期间动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。

  2. OSHI(Operating System and Hardware Information)是一个开源的Java库,用于获取和操作操作系统和硬件信息。它提供了一组简单易用的API,可以用于检索和监控诸如操作系统类型、处理器信息、内存使用情况、硬盘信息、网络接口等系统和硬件相关的数据。

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.4.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.14.0</version>
</dependency>

更多版本:mvnrepository

模型

  1. CpuModel

    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
    package com.heifan.code.domain.monitor;

    import com.alibaba.fastjson.annotation.JSONField;
    import io.swagger.v3.oas.annotations.media.Schema;
    import lombok.Data;

    /**
    *
    * @author HiF
    * @date 2024/8/9 10:43
    */
    @Data
    public class CpuModel {
    @Schema(description = "cpu名称")
    private String name;
    @Schema(description = "物理CPU个数")
    @JSONField(name="package")
    private String packageName;
    @Schema(description = "CPU内核个数")
    private String core;
    @Schema(description = "内核个数")
    private int coreNumber;
    @Schema(description = "逻辑CPU个数")
    private String logic;
    @Schema(description = "CPU已用百分比")
    private String used;
    @Schema(description = "未用百分比")
    private String idle;
    }
  2. DiskModel

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.heifan.code.domain.monitor;

    import io.swagger.v3.oas.annotations.media.Schema;
    import lombok.Data;

    /**
    *
    * @author HiF
    * @date 2024/8/9 10:44
    */
    @Data
    public class DiskModel {
    @Schema(description = "硬盘总容量")
    private String total;
    @Schema(description = "空闲硬盘")
    private String available;
    @Schema(description = "已使用")
    private String used;
    @Schema(description = "已使用百分比")
    private String usageRate;
    }
  3. MemoryModel

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.heifan.code.domain.monitor;

    import io.swagger.v3.oas.annotations.media.Schema;
    import lombok.Data;

    /**
    *
    * @author HiF
    * @date 2024/8/9 10:44
    */
    @Data
    public class MemoryModel {
    @Schema(description = "总内存")
    private String total;
    @Schema(description = "空闲内存")
    private String available;
    @Schema(description = "已使用")
    private String used;
    @Schema(description = "已使用百分比")
    private String usageRate;
    }
  4. MonitorListVO

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package com.heifan.code.domain.monitor;

    import io.swagger.v3.oas.annotations.media.Schema;
    import lombok.Data;

    /**
    *
    * @author HiF
    * @date 2024/8/9 10:44
    */
    @Data
    public class MonitorListVO {
    @Schema(description = "系统信息")
    private SystemModel system;
    @Schema(description = "CPU信息")
    private CpuModel cpu;
    @Schema(description = "内存信息")
    private MemoryModel memory;
    @Schema(description = "硬盘信息")
    private DiskModel disk;
    @Schema(description = "当前时间")
    private Long time;
    }
  5. SwapModel

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package com.heifan.code.domain.monitor;

    import lombok.Data;

    /**
    *
    * @author HiF
    * @date 2024/8/9 10:44
    */
    @Data
    public class SwapModel {
    private String total;
    private String available;
    private String used;
    private String usageRate;
    }
  6. SystemModel

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package com.heifan.code.domain.monitor;

    import io.swagger.v3.oas.annotations.media.Schema;
    import lombok.Data;

    /**
    *
    * @author HiF
    * @date 2024/8/9 10:44
    */
    @Data
    public class SystemModel {
    @Schema(description = "系统")
    private String os;
    @Schema(description = "服务器IP")
    private String ip;
    @Schema(description = "运行时间")
    private String day;
    }

工具类

MonitorUtil

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package com.heifan.code.utils;

import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import com.heifan.code.domain.monitor.*;
import lombok.Data;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
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.FormatUtil;
import oshi.util.Util;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

/**
* 系统信息工具
* @author HiF
* @date 2024/8/9 10:43
*/
@Data
public class MonitorUtil {

private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00");
private CpuModel cpu = null;
private DiskModel disk = null;
private MemoryModel memory = null;
private SwapModel swap = null;
private SystemModel system = null;

public MonitorUtil() {
try {
SystemInfo si = new SystemInfo();
OperatingSystem os = si.getOperatingSystem();
HardwareAbstractionLayer hal = si.getHardware();
this.cpu = getCpuInfo(hal.getProcessor());
this.memory = getMemoryInfo(hal.getMemory());
this.disk = getDiskInfo(os);
this.system = getSystemInfo(os);
this.swap = getSwapInfo(hal.getMemory());
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 获取磁盘信息
*
* @return /
*/
private DiskModel getDiskInfo(OperatingSystem os) {
DiskModel diskInfo = new DiskModel();
FileSystem fileSystem = os.getFileSystem();
List<OSFileStore> fsArray = fileSystem.getFileStores();
long total = 0L;
long available = 0L;
long used = 0L;
for (OSFileStore fs : fsArray) {
total += fs.getTotalSpace();
available += fs.getUsableSpace();
}
used = total - available;
diskInfo.setTotal(FormatUtil.formatBytes(total));
diskInfo.setAvailable(FormatUtil.formatBytes(available));
diskInfo.setUsed(FormatUtil.formatBytes(used));
diskInfo.setUsageRate(DECIMAL_FORMAT.format(used / (double) total * 100));
return diskInfo;
}

/**
* 获取交换区信息
*
* @param memory /
* @return /
*/
private SwapModel getSwapInfo(GlobalMemory memory) {
SwapModel swapInfo = new SwapModel();
swapInfo.setTotal(FormatUtil.formatBytes(memory.getVirtualMemory().getSwapTotal()));
swapInfo.setAvailable(FormatUtil.formatBytes(memory.getVirtualMemory().getSwapTotal() - memory.getVirtualMemory().getSwapUsed()));
swapInfo.setUsageRate(DECIMAL_FORMAT.format(memory.getVirtualMemory().getSwapUsed() / (double) memory.getVirtualMemory().getSwapTotal() * 100));
swapInfo.setUsed(FormatUtil.formatBytes(memory.getVirtualMemory().getSwapUsed()));
return swapInfo;
}

/**
* 获取内存信息
*
* @param memory /
* @return /
*/
private MemoryModel getMemoryInfo(GlobalMemory memory) {
MemoryModel memoryInfo = new MemoryModel();
memoryInfo.setTotal(FormatUtil.formatBytes(memory.getTotal()));
memoryInfo.setAvailable(FormatUtil.formatBytes(memory.getAvailable()));
memoryInfo.setUsed(FormatUtil.formatBytes(memory.getTotal() - memory.getAvailable()));
memoryInfo.setUsageRate(DECIMAL_FORMAT.format((memory.getTotal() - memory.getAvailable()) / (double) memory.getTotal() * 100));
return memoryInfo;
}

/**
* 获取Cpu相关信息
*
* @param processor /
* @return /
*/
private CpuModel getCpuInfo(CentralProcessor processor) {
CpuModel cpuInfo = new CpuModel();
cpuInfo.setName(processor.getProcessorIdentifier().getName());
cpuInfo.setPackageName(processor.getPhysicalPackageCount() + "个物理CPU");
cpuInfo.setCore(processor.getPhysicalProcessorCount() + "个物理核心");
cpuInfo.setCoreNumber(processor.getPhysicalProcessorCount());
cpuInfo.setLogic(processor.getLogicalProcessorCount() + "个逻辑CPU");
// CPU信息
long[] prevTicks = processor.getSystemCpuLoadTicks();
// 等待1秒...
Util.sleep(1000);
long[] ticks = processor.getSystemCpuLoadTicks();
long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
long totalCpu = user + nice + sys + idle + iowait + irq + softirq + steal;
cpuInfo.setUsed(DECIMAL_FORMAT.format(100d * user / totalCpu + 100d * sys / totalCpu));
cpuInfo.setIdle(DECIMAL_FORMAT.format(100d * idle / totalCpu));
return cpuInfo;
}

/**
* 获取系统相关信息,系统、运行天数、系统IP
*
* @param
* @return /
*/
private SystemModel getSystemInfo(OperatingSystem operatingSystem) {
SystemModel systemInfo = new SystemModel();
String osName = System.getProperty("os.name");
String os = osName;
if(osName.contains("Linux")){
os = operatingSystem.toString();
}
// jvm 运行时间
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
Date date = new Date(time);
// 计算项目运行时间
String formatBetween = DateUtil.formatBetween(date, new Date(), BetweenFormatter.Level.HOUR);
// 系统信息
systemInfo.setOs(os);
systemInfo.setDay(formatBetween);
systemInfo.setIp(getLocalhostIp());
return systemInfo;
}

/**
* <p>获取当前服务器所有符合条件的网络地址</p>
*
* @return List<InetAddress> 网络地址列表
* @throws Exception 默认异常
*/
private static String getLocalhostIp() {
List<String> result = new ArrayList<>();
try {
// 遍历所有的网络接口
for (Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements(); ) {
NetworkInterface ni = (NetworkInterface) networkInterfaces.nextElement();
// 在所有的接口下再遍历IP
for (Enumeration addresses = ni.getInetAddresses(); addresses.hasMoreElements(); ) {
InetAddress address = (InetAddress) addresses.nextElement();
//排除LoopbackAddress、SiteLocalAddress、LinkLocalAddress、MulticastAddress类型的IP地址
if (!address.isLoopbackAddress()
/*&& !inetAddr.isSiteLocalAddress()*/
&& !address.isLinkLocalAddress() && !address.isMulticastAddress()) {
String hostAddress = address.getHostAddress();
result.add(hostAddress);
}
}
}
}catch (Exception e) {

}
String ip = String.join(",",result);
return ip;
}
}

使用

1
2
3
4
5
6
7
@GetMapping("/get")
public Object getTest(HttpServletRequest request, HttpServletResponse response){
MonitorUtil monitorUtil = new MonitorUtil();
MonitorListVO vo = JsonUtil.getJsonToBean(monitorUtil, MonitorListVO.class);
vo.setTime(System.currentTimeMillis());
return Result.success(JsonUtil.getObjectToString(vo));
}

效果

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
{
"cpu": {
"core": "12个物理核心",
"coreNumber": 12,
"idle": "99.16",
"logic": "20个逻辑CPU",
"name": "12th Gen Intel(R) Core(TM) i7-12700",
"package": "1个物理CPU",
"used": "0.76"
},
"disk": {
"available": "1.9 TiB",
"total": "2.3 TiB",
"usageRate": "16.87",
"used": "392.6 GiB"
},
"memory": {
"available": "10.4 GiB",
"total": "31.8 GiB",
"usageRate": "67.29",
"used": "21.4 GiB"
},
"system": {
"day": "0小时",
"ip": "240e:391:ec3:b1f0:fc63:d:ddb9:b954,240e:391:ec3:b1f0:a761:c4e6:c793:630c,240e:391:ec3:b1f0:0:0:0:5,192.168.0.18,192.168.23.1,192.168.19.1",
"os": "Windows 11"
},
"time": 1723171274502
}

可能遇到的问题

runtime exception:Unmapped relationship: 7

1
2
3
4
5
6
7
8
9
{
"msg_type": "text",
"content": {
"text": "### 告警信息\n>工程名:heifan-code-test\n>类路径:com.sun.jna.platform.win32.WinNT$SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX\n>方法名:fromPointer\n>链路标志:ffffffffb22a3b4700000000176875cf1723170856222000\n>异常标志:391f1227963e37a5cf16e2d394310ad4\n>异常扩展信息: ip: 192.168.0.18:50081 pid 24256Unmapped relationship: 7\r\n异常信息:java.lang.IllegalStateException: Unmapped relationship: 7\n>>异常追踪:\n`com.sun.jna.platform.win32.WinNT$SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.fromPointer(WinNT.java:2999),com.sun.jna.platform.win32.Kernel32Util.getLogicalProcessorInformationEx(Kernel32Util.java:715),oshi.driver.windows.LogicalProcessorInformation.getLogicalProcessorInformationEx(LogicalProcessorInformation.java:61)\r\n`\n"
},
"atMobiles": [
null
]
}

解决方法:降低jna-platform的版本。上述两个版本实测兼容。

总结

从成熟的项目里还是能学到东西的。