[CodeStats]3D实时监控实战:从自研JavaWeb框架到系统时空穿梭机

📌 作者介绍

哈喽,我是 CodeStats。

一个在底层技术上"考古"了四年的硬核爱好者,也是 WWAIC(全周项目AI编程 ) 范式的提出者和实践者。我曾手写过一个完整的Java Web框架(从IoC容器到嵌入式Tomcat,代码全开源),也喜欢用通俗的语言拆解CPU、JVM、操作系统的运行本质。

我一直相信,计算机科学没有魔法。所有看似神奇的效果------无论是java -jar一键启动,还是多线程自动切换------底层都是简单的规则层层组合

一、引言

在 Java 后端开发中,Spring 生态已然成为事实标准。然而,当我们亲手实现一个微型 Spring + Tomcat 时,才能真正理解 IoC 容器如何管理 Bean、DispatcherServlet 如何分发请求、连接池如何限流。

CodeStats 正是一个完全自研的"类 Spring"框架,它集成了 IoC 容器、MVC 架构、嵌入式 Tomcat、JDBC 连接池、MyBatis 风格 Mapper 以及代码分析引擎。

更值得一提的是,CodeStats 是 WWAIC(Whole-Week AI Engineering,全周项目 AI 工程) 范式的首个实证项目------100% 由 AI 生成,耗时仅一周,实现了从 IoC 容器到嵌入式 Tomcat 的全栈能力。

今天,我将带你深入 CodeStats 最新实现的 3D 实时监控模块,看看如何用 Three.js + Java 打造一个"系统时空穿梭机"!

二、CodeStats 项目介绍

2.1 一分钟快速启动

bash

复制代码
# 下载并解压
unzip CodeStats-1.0.zip && cd CodeStats
java -jar CodeStats-1.0.jar
# 浏览器访问 http://localhost:28080/

无需任何配置------不配置数据库,核心功能完整可用。

2.2 技术架构全景

CodeStats 从 Socket 开始,手写了整套基础设施:

模块 自研实现 说明
Web 容器 BIO/NIO 线程池 + Pipeline-Valve 责任链 模拟 Tomcat 架构
IoC 容器 包扫描 + 反射注入 + 单例池 @Controller/@Service/@Autowired
MVC 框架 DispatcherServlet + HandlerMapping + 参数绑定 @RequestMapping/@ResponseBody
ORM 框架 MapperProxy 动态代理 + 注解 SQL @Mapper/@Select,自动映射结果
连接池 阻塞队列 + Semaphore 并发控制 支持空闲回收、连接验证
日志框架 Appender + Layout + XML 配置 异步/滚动文件/级别过滤
缓存框架 ConcurrentHashMap + TTL + 定期清理 可选 Caffeine 扩展
前端框架 Proxy + Dep + Watcher 响应式系统 自研类 Vue 框架 SimpleVue

2.3 功能矩阵

CodeStats 不仅是一个框架,更是一套完整的开发工具集:

  • 代码分析引擎:多线程并行统计(总行数、代码行、注释行、空行、复杂度),支持 GitIgnore 过滤、扩展名筛选、排除路径,提供 Web 界面 / Swing GUI / 命令行 三种模式

  • 目录管理:树形导航、文件/目录 CRUD、文本在线编辑、目录打包 ZIP 下载

  • AI Agent:Ollama 本地模型、DeepSeek API、自定义 API、内置知识库"项目助手"

  • 数据库浏览器:连接 MySQL,动态加载数据库/表/列信息

三、3D 实时监控:设计思路

3.1 为什么需要 3D 实时监控?

传统的系统监控面板以表格和 2D 图表为主,信息密度高但缺乏空间感。3D 可视化可以将线程状态、内存使用、连接池、请求统计等多维数据在同一个三维空间中呈现,让系统状态一目了然。

3.2 整体架构

text

复制代码
┌─────────────────────────────────────────────────────────────┐
│                      前端 (Three.js)                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │  3D 线程图   │  │  内存柱状图  │  │  粒子流调用链展示   │ │
│  └─────────────┘  └─────────────┘  └─────────────────────┘ │
│                           ↕ REST API                        │
├─────────────────────────────────────────────────────────────┤
│                    后端 (Java / CodeStats)                  │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │              JvmMonitorService                          │ │
│  │  • ThreadMXBean 采集线程状态                            │ │
│  │  • Runtime 采集内存信息                                 │ │
│  │  • DataSourceUtils 采集连接池状态                       │ │
│  │  • TraceContextHolder 采集请求调用链                    │ │
│  └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

3.3 数据采集层(后端)

后端核心是 JvmMonitorService,它聚合了四类数据:

  1. 线程状态 :通过 ThreadMXBean 获取所有线程的运行状态(RUNNING/BLOCKED/WAITING 等)

  2. 内存信息 :通过 Runtime 获取堆内存和非堆内存使用情况

  3. 连接池状态 :通过 DataSourceUtils.getPoolStats() 获取活跃/空闲连接数

  4. 请求调用链 :通过 TraceContextHolder 获取每个请求的调用链路

3.4 可视化层(前端)

前端基于 Three.js 构建 3D 场景,包含四大可视化组件:

  • 线程柱状图:不同颜色代表不同线程状态,柱高代表数量

  • 内存环形图:堆内存和非堆内存的占用比例

  • 连接池水位图:动态显示连接池的活跃/空闲情况

  • 粒子流调用链:实时展示最新活跃线程的方法调用链路

四、核心代码片段

4.1 后端:线程详情采集(含 lastActiveTime)

java

复制代码
// JvmMonitorService.java
private List<Map<String, Object>> getThreadDetails() {
    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
    long[] allThreadIds = threadMXBean.getAllThreadIds();
    ThreadInfo[] infos = threadMXBean.getThreadInfo(allThreadIds, 20);
    Map<Long, TraceContextHolder.TraceContext> contextMap = 
        TraceContextHolder.getAllContexts();
    List<Map<String, Object>> details = new ArrayList<>();

    for (ThreadInfo info : infos) {
        if (info == null) continue;
        Map<String, Object> item = new LinkedHashMap<>();
        long tid = info.getThreadId();
        item.put("threadId", tid);
        item.put("threadName", info.getThreadName());
        item.put("state", info.getThreadState().name());

        TraceContextHolder.TraceContext ctx = contextMap.get(tid);
        String callChain = null;
        String status = "IDLE";
        long lastActiveTime = 0;

        if (ctx != null) {
            if (ctx.endTime == 0) {
                status = "RUNNING";
                lastActiveTime = System.currentTimeMillis();
                callChain = ctx.nodePath != null ? ctx.nodePath : "Dispatcher";
            } else {
                status = "COMPLETED";
                lastActiveTime = ctx.endTime;
                callChain = ctx.nodePath != null ? ctx.nodePath : "Completed";
            }
        }

        item.put("callChain", callChain != null ? callChain : "");
        item.put("status", status);
        item.put("lastActiveTime", lastActiveTime);  // ★ 关键排序字段

        if ("RUNNING".equals(status) && callChain != null) {
            String[] nodes = callChain.split(" → ");
            item.put("nodes", nodes);
        } else {
            item.put("nodes", new String[0]);
        }
        details.add(item);
    }
    return details;
}

4.2 后端:聚合监控数据接口

java

复制代码
// JvmMonitorService.java
public Map<String, Object> getAggregatedMonitorData() {
    Map<String, Object> result = new HashMap<>();
    result.put("threads", getAllThreadsInfo());      // 线程统计
    result.put("memory", getMemoryInfo());            // 内存信息
    result.put("pool", DataSourceUtils.getPoolStats()); // 连接池
    result.put("requests", getRequestStats());        // 请求统计
    result.put("threadDetails", getThreadDetails());  // ★ 线程详情
    return result;
}

4.3 前端:线程排序与粒子流更新

javascript

复制代码
// realtime-monitor.js - 核心排序逻辑
function updateScene(data) {
    // 按状态优先级 + 时间降序排序
    const statusPriority = {
        'RUNNING': 1,   // 运行排第一
        'BLOCKED': 2,   // 阻塞排第二
        'WAITING': 3,
        'TIMED_WAITING': 4,
        'NEW': 5,
        'TERMINATED': 6,
        'IDLE': 7,
        'COMPLETED': 8
    };
    
    const sortedThreads = [...data.threadDetails].sort((a, b) => {
        const priA = statusPriority[a.status] || 9;
        const priB = statusPriority[b.status] || 9;
        if (priA !== priB) return priA - priB;
        const timeA = a.lastActiveTime || a.startTime || 0;
        const timeB = b.lastActiveTime || b.startTime || 0;
        return timeB - timeA;  // 降序,最新在前
    });

    // 线程列表使用排序后的数据
    renderThreadList(sortedThreads);
    
    // 粒子流使用排序后的数据(取第一条线程的调用链)
    if (cleanupThreadFlow) {
        updateThreadFlowData(sortedThreads);
    }
}

4.4 前端:粒子流节点动态渲染

javascript

复制代码
// thread-flow-module.js
function renderThreadFlows(threads) {
    clearGraph();  // 清空旧节点和连线

    const firstThread = threads[0];
    let nodeNames = firstThread.nodes || [];

    // 如果 nodes 为空,从 callChain 解析
    if (!nodeNames || nodeNames.length === 0) {
        if (firstThread.callChain) {
            nodeNames = firstThread.callChain.split(' → ')
                .map(s => s.trim()).filter(s => s.length > 0);
        }
    }

    const nodeCount = nodeNames.length;
    // ★ 根据节点数量动态生成位置
    const positions = generateNodePositions(nodeCount, -6, 6, 0);

    // 为每个节点创建球体 + 标签
    for (let i = 0; i < nodeCount; i++) {
        const sphere = new THREE.Mesh(sphereGeo, material);
        sphere.position.copy(positions[i]);
        sphere.userData = { nodeName: nodeNames[i] };
        nodesGroup.add(sphere);
        // 添加 CSS2D 标签...
    }

    // 节点 > 1 时,绘制连线和粒子流
    if (nodeCount > 1) {
        // 绘制连线...
        // 创建粒子系统沿路径流动...
    }
}

4.5 核心:动态生成节点位置(起点固定)

javascript

复制代码
function generateNodePositions(nodeCount, startX = -6, endX = 6, y = 0) {
    const positions = [];
    if (nodeCount === 0) return positions;
    if (nodeCount === 1) {
        positions.push(new THREE.Vector3(0, y, 0));  // 单节点居中
        return positions;
    }
    // 多节点均匀分布,第一个节点固定在 startX
    for (let i = 0; i < nodeCount; i++) {
        const t = i / (nodeCount - 1);
        const x = startX + t * (endX - startX);
        const z = Math.sin(i * 1.3) * 0.4;  // 轻微 Z 轴错落
        positions.push(new THREE.Vector3(x, y, z));
    }
    return positions;
}

五、效果展示

如上图所示,3D 实时监控大屏包含:

区域 内容
左侧 3D 场景 线程柱状图(颜色区分状态)、内存环形图、连接池水位
右侧线程列表 按运行/阻塞优先 + 时间最新排序,展示线程 ID、名称、状态、调用链
底部粒子流 实时展示最新活跃线程的方法调用链路,节点数动态变化,粒子沿路径流动
请求统计 总请求数、运行中、错误数、平均响应时间、最近请求

六、项目地址与资源

6.1 开源仓库

Gitee 开源仓库: https://gitee.com/zhouzuoli/code-stats.git

6.2 快速体验

bash

复制代码
git clone https://gitee.com/zhouzuoli/code-stats.git
cd code-stats
java -jar CodeStats-1.0.jar
# 访问 http://localhost:28080/
# 点击顶部导航栏 「3D 依赖图」→「实时监控」

6.3 相关文章

七、总结

CodeStats 的 3D 实时监控模块展示了从自研 Java 框架到三维可视化的完整链路

  1. 后端:通过 JMX 和自研 TraceContext 采集线程、内存、连接池、调用链数据

  2. 排序逻辑:运行/阻塞优先 + lastActiveTime 降序,确保最新活跃线程排在最前

  3. 前端:Three.js 构建 3D 场景,粒子流动态展示调用链,节点数量随调用链长度动态变化

  4. 起点固定:第一个节点始终固定在左侧,便于观察调用链的起始位置

如果你也想拥有一个属于自己的 Java 框架,或者需要一个轻量级的系统监控工具,不妨 Clone 下来试试。有任何问题欢迎在评论区留言!