You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot应用中不使用JMX监控Tomcat内部线程池

获取Tomcat线程池指标(无需JMX)

Great question! You’re absolutely correct that Tomcat’s AbstractEndpoint (and concrete implementations like Nio2Endpoint) expose the thread pool metrics you need via direct methods like getCurrentThreadCount() and getCurrentThreadsBusy(). The trick is accessing those Endpoint instances directly within your Spring Boot app—here are two reliable ways to do it without relying on JMX:

1. 通过Spring Boot的Tomcat Web Server实例获取Endpoint

Spring Boot wraps Tomcat’s internal components, so you can access the underlying Tomcat instance and its endpoints through the auto-configured web server bean. Here’s a working example for modern Spring Boot versions (2.x+):

import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardService;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.WebServer;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class TomcatThreadPoolMetricsCollector {

    private final WebServer webServer;

    // 注入Spring Boot自动配置的WebServer
    public TomcatThreadPoolMetricsCollector(WebServer webServer) {
        this.webServer = webServer;
    }

    @PostConstruct
    public void collectThreadPoolMetrics() {
        if (webServer instanceof TomcatWebServer) {
            TomcatWebServer tomcatWebServer = (TomcatWebServer) webServer;
            StandardService service = (StandardService) tomcatWebServer.getTomcat().getService();

            // 遍历所有Connector(如果有多个HTTP/HTTPS连接器的情况)
            for (Connector connector : service.findConnectors()) {
                AbstractEndpoint<?> endpoint = (AbstractEndpoint<?>) connector.getProtocolHandler().getEndpoint();
                
                if (endpoint != null) {
                    int currentThreads = endpoint.getCurrentThreadCount();
                    int busyThreads = endpoint.getCurrentThreadsBusy();
                    int maxThreads = endpoint.getMaxThreads();

                    // 这里可以将指标暴露给Prometheus、日志输出或其他监控系统
                    System.out.printf("Tomcat线程池统计 - 当前线程数: %d, 忙碌线程数: %d, 最大线程数: %d%n",
                            currentThreads, busyThreads, maxThreads);
                }
            }
        }
    }
}

如果是旧版Spring Boot(1.x),只需将TomcatWebServer替换为TomcatEmbeddedServletContainer,并调整注入逻辑即可。

2. 复用Spring Boot Actuator的Tomcat指标逻辑

如果你已经在使用Spring Boot Actuator,它正是通过这种直接访问Endpoint的方式收集Tomcat线程池指标的。你可以:

  • 开启tomcat指标端点(通过配置management.endpoints.web.exposure.include=tomcat),直接将这些指标抓取到Prometheus中。
  • 参考TomcatMetrics类的源码(Actuator的核心类),学习它如何安全地访问Endpoint实例,然后在自定义代码中复用类似逻辑。

关键注意事项

  • 版本兼容性: Tomcat的内部API(如AbstractEndpoint)虽然稳定,但不同大版本(如Tomcat 8.x vs 10.x)可能有细微变化,需要结合你Spring Boot内嵌的Tomcat版本测试。
  • 内部API提示: 这些类属于Tomcat的内部实现,而非官方公开API。虽然不会轻易断裂,但升级Tomcat/Spring Boot大版本时,可能需要调整代码。
  • 多连接器支持: 如果应用使用了多个连接器(比如同时开启HTTP和HTTPS),要记得遍历所有连接器,获取每个线程池的指标。

这种方式让你无需JMX远程连接,直接在应用进程内获取指标,完全符合你的需求。

内容的提问来源于stack exchange,提问作者Patrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:16:06