Spark API
基本信息
| 属性 | 值 |
|---|---|
| 公共 API 模块 | spark-api(8 个 .java 文件) |
| 入口 | me.lucko.spark.api.SparkProvider.get() |
| 接口 | me.lucko.spark.api.Spark |
| 实现 | me.lucko.spark.common.api.SparkApi(在 spark-common 中,spark-common shade 进 1710 jar) |
| 注册时机 | 平台 enable() 中 SparkApi.register(api) |
| 注销时机 | 平台 disable() 中 SparkApi.unregister() |
spark 提供一个单例门面,让其他模组以编程方式读取性能统计,而不必解析聊天输出。
获取实例
Spark spark = SparkProvider.get();
SparkProvider.get() 在实例未注册时抛 IllegalStateException("spark has not loaded yet!") —— 不是返回 null。因此依赖方必须自己处理「spark 尚未加载」的情况(典型做法是包一层 try/catch 或延迟初始化)。
在 1.7.10 上,SparkPlatform.enable() 由 Forge1710ServerSparkPlugin.register()(FMLServerStartingEvent 阶段)与 Forge1710ClientSparkPlugin.register()(FMLInitializationEvent 客户端阶段)触发,因此:
- 服务端可在
FMLServerStartingEvent之后安全获取 - 服务端在
FMLPreInitializationEvent阶段尚不可用
反射式单例注入
SparkApi 与 SparkProvider 分属不同模块,SparkProvider.set 是包级私有方法,因此通过反射调用(SparkApi.java:50-57):
private static final Method SINGLETON_SET_METHOD;
static {
try {
SINGLETON_SET_METHOD = SparkProvider.class.getDeclaredMethod("set", Spark.class);
SINGLETON_SET_METHOD.setAccessible(true);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
register(Spark) 调用 SINGLETON_SET_METHOD.invoke(null, spark),unregister() 调用 invoke(null, new Object[]{null})(把单位置空)。两者都只 catch (ReflectiveOperationException e) { e.printStackTrace(); }。
SparkPlugin 另有 registerApi(Spark) 钩子(SparkPlugin.java:206),1.7.10 未覆写,保持接口默认的空实现;实际生效的是上面的静态 SparkApi.register。
5 个统计方法
| 方法 | 返回类型 | 可为 null | 说明 |
|---|---|---|---|
cpuProcess() |
DoubleStatistic<CpuUsage> |
否 | 进程 CPU 占用 |
cpuSystem() |
DoubleStatistic<CpuUsage> |
否 | 系统 CPU 占用 |
tps() |
DoubleStatistic<TicksPerSecond> |
是 | 平台不支持 tick 统计时返回 null |
mspt() |
GenericStatistic<DoubleAverageInfo, MillisPerTick> |
是 | stats == null 或 !stats.isDurationSupported() 时返回 null |
gc() |
Map<String, GarbageCollector> |
否 | 收集器名 → 统计(@Unmodifiable) |
tps() 与 mspt() 是可空的,调用方必须判空。在 1.7.10 上二者均可用(Forge1710TickHook 与 Forge1710TickReporter 都已注册),但 API 层面仍按可空设计。
统计窗口
StatisticWindow 的三个枚举定义了各指标的滚动平均窗口,与 /spark tps 的命令行输出窗口一致:
| 枚举 | 窗口 |
|---|---|
CpuUsage |
SECONDS_10 / MINUTES_1 / MINUTES_15 |
TicksPerSecond |
SECONDS_5 / SECONDS_10 / MINUTES_1 / MINUTES_5 / MINUTES_15 |
MillisPerTick |
SECONDS_10 / MINUTES_1 / MINUTES_5 |
每个窗口实现 length() 返回 java.time.Duration。
Statistic<W> 接口只有两个方法:name()(统计名,如 "CPU Process Usage")与 getWindows()(可用窗口数组)。
GarbageCollector
gc() 返回的每个条目提供:
| 方法 | 返回 |
|---|---|
name() |
收集器名 |
totalCollections() |
累计回收次数 |
totalTime() |
累计回收耗时 |
avgTime() |
平均单次耗时 |
avgFrequency() |
平均回收间隔 |
1.7.10 上的语义差异
与 /spark ping 的情况不同,API 本身在 1.7.10 上是完整可用的 —— TPS / MSPT / CPU / GC 四类统计都来自已接线的 Forge1710TickHook、Forge1710TickReporter 与 CpuMonitor。
但要注意 gc() 的时间基准:其内部用 platform.getServerNormalOperationStartTime() 计算 serverUptime,与 /spark gc 命令一样,是相对「服务器正常运营时刻」而非 JVM 启动时刻。
另外 ping 没有对应的 API 方法 —— Spark 接口不提供玩家延迟查询,1.7.10 上该数据源也未接线(详见 ping 条目的死代码分析)。
数值
| 数值名 | 值 | 来源 |
|---|---|---|
| API 方法数 | 5 | Spark 接口 |
| 公共 API 文件数 | 8 | spark-api 模块 .java 计数 |
| 可为 null 的方法数 | 2(tps()、mspt()) |
Spark 接口的 @Nullable 标注 |
CpuUsage 窗口数 |
3 | StatisticWindow.CpuUsage |
TicksPerSecond 窗口数 |
5 | StatisticWindow.TicksPerSecond |
MillisPerTick 窗口数 |
3 | StatisticWindow.MillisPerTick |
| 未注册时的行为 | 抛 IllegalStateException |
SparkProvider.get |
相关条目
- /spark tps - 同一批统计的命令行视图
- /spark gc - 同一批 GC 统计的命令行视图
- config.json 配置项 - API 读取的数据不受端点配置影响