項目結構

threadpool-monitor/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── zhangxueliang/
│   │   │       └── monitor/
│   │   │           ├── ThreadPoolMonitorStarter.java
│   │   │           ├── annotation/
│   │   │           │   ├── EnableThreadPoolMonitor.java
│   │   │           │   └── MonitorThreadPool.java
│   │   │           ├── config/
│   │   │           │   ├── MonitorProperties.java
│   │   │           │   └── ThreadPoolAutoConfig.java
│   │   │           ├── core/
│   │   │           │   ├── MonitorableThreadPoolExecutor.java
│   │   │           │   ├── ThreadPoolMonitor.java
│   │   │           │   └── ThreadPoolRegistry.java
│   │   │           ├── endpoint/
│   │   │           │   ├── ThreadPoolEndpoint.java
│   │   │           │   └── ThreadPoolEndpointConfig.java
│   │   │           ├── metrics/
│   │   │           │   └── ThreadPoolMetrics.java
│   │   │           ├── web/
│   │   │           │   ├── ThreadPoolMonitorController.java
│   │   │           │   └── ThreadPoolStatistics.java
│   │   │           └── advice/
│   │   │               └── ThreadPoolAdvice.java
│   │   └── resources/
│   │       ├── META-INF/
│   │       │   └── spring.factories
│   │       └── static/
│   │           └── monitor.html
│   └── test/
└── README.md

1. Maven配置文件 (pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>zhangxueliang</groupId>
    <artifactId>threadpool-monitor</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <name>ThreadPool Monitor</name>
    <description>Spring Boot Thread Pool Monitoring Starter</description>
    
    <properties>
        <java.version>1.8</java.version>
        <spring-boot.version>2.0.6.RELEASE</spring-boot.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <dependencies>
        <!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring Boot Starter AOP -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        
        <!-- Spring Boot Actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- JSON Processing -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        
        <!-- 測試依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <classifier>exec</classifier>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>1.18.4</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2. 啓動器類

package zhangxueliang.monitor;

import org.springframework.context.annotation.Import;
import zhangxueliang.monitor.config.ThreadPoolAutoConfig;

import java.lang.annotation.*;

/**
 * 啓用線程池監控註解
 * 在Spring Boot應用上添加此註解即可啓用線程池監控
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ThreadPoolAutoConfig.class)
public @interface EnableThreadPoolMonitor {
}

3. 自動配置類

package zhangxueliang.monitor.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import zhangxueliang.monitor.ThreadPoolMonitorStarter;
import zhangxueliang.monitor.core.ThreadPoolMonitor;
import zhangxueliang.monitor.core.ThreadPoolRegistry;

/**
 * 線程池自動配置類
 */
@Configuration
@EnableConfigurationProperties(MonitorProperties.class)
@ConditionalOnProperty(prefix = "threadpool.monitor", name = "enabled", havingValue = "true", matchIfMissing = true)
public class ThreadPoolAutoConfig {

    @Bean
    @ConditionalOnMissingBean
    public ThreadPoolRegistry threadPoolRegistry() {
        return new ThreadPoolRegistry();
    }

    @Bean
    @ConditionalOnMissingBean
    public ThreadPoolMonitor threadPoolMonitor(ThreadPoolRegistry registry,
                                              MonitorProperties properties) {
        return new ThreadPoolMonitor(registry, properties);
    }

    @Bean
    public ThreadPoolMonitorStarter threadPoolMonitorStarter(ThreadPoolRegistry registry,
                                                            MonitorProperties properties) {
        return new ThreadPoolMonitorStarter(registry, properties);
    }
}

4. 配置屬性類

package zhangxueliang.monitor.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * 監控配置屬性
 */
@Data
@ConfigurationProperties(prefix = "threadpool.monitor")
public class MonitorProperties {
    
    /**
     * 是否啓用監控
     */
    private boolean enabled = true;
    
    /**
     * 監控端點路徑
     */
    private String endpointPath = "/threadpool/monitor";
    
    /**
     * 是否啓用Web控制枱
     */
    private boolean webEnabled = true;
    
    /**
     * Web控制枱路徑
     */
    private String webPath = "/threadpool/console";
    
    /**
     * 是否啓用Actuator端點
     */
    private boolean actuatorEnabled = true;
    
    /**
     * Actuator端點ID
     */
    private String actuatorId = "threadpool";
    
    /**
     * 監控數據刷新間隔(毫秒)
     */
    private int refreshInterval = 5000;
    
    /**
     * 告警配置
     */
    private AlertConfig alert = new AlertConfig();
    
    @Data
    public static class AlertConfig {
        /**
         * 隊列使用率告警閾值(0-100)
         */
        private int queueUsageThreshold = 80;
        
        /**
         * 活躍線程告警閾值(0-100)
         */
        private int activeThreadThreshold = 80;
        
        /**
         * 任務拒絕告警閾值
         */
        private int rejectionThreshold = 10;
        
        /**
         * 任務失敗率告警閾值(0-100)
         */
        private int failureRateThreshold = 10;
        
        /**
         * 是否啓用郵件告警
         */
        private boolean emailAlert = false;
        
        /**
         * 是否啓用日誌告警
         */
        private boolean logAlert = true;
    }
}

5. 啓動器實現類

package zhangxueliang.monitor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import zhangxueliang.monitor.config.MonitorProperties;
import zhangxueliang.monitor.core.ThreadPoolRegistry;

/**
 * 線程池監控啓動器
 */
@Component
@Slf4j
public class ThreadPoolMonitorStarter implements CommandLineRunner {

    private final ThreadPoolRegistry registry;
    private final MonitorProperties properties;

    @Autowired
    public ThreadPoolMonitorStarter(ThreadPoolRegistry registry,
                                   MonitorProperties properties) {
        this.registry = registry;
        this.properties = properties;
    }

    @Override
    public void run(String... args) {
        log.info("線程池監控組件已啓動");
        log.info("監控端點: {}", properties.getEndpointPath());
        log.info("Web控制枱: {}", properties.getWebPath());
        log.info("刷新間隔: {}ms", properties.getRefreshInterval());
        
        if (properties.isActuatorEnabled()) {
            log.info("Actuator端點已啓用: /actuator/{}", properties.getActuatorId());
        }
    }
}

6. 監控註解

package zhangxueliang.monitor.annotation;

import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.AsyncConfigurer;

import java.lang.annotation.*;
import java.util.concurrent.Executor;

/**
 * 監控線程池註解
 * 可以標註在方法或類上,自動創建並監控線程池
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MonitorThreadPool {
    
    /**
     * 線程池名稱
     */
    String value() default "";
    
    /**
     * 核心線程數
     */
    int corePoolSize() default 5;
    
    /**
     * 最大線程數
     */
    int maximumPoolSize() default 10;
    
    /**
     * 隊列容量
     */
    int queueCapacity() default Integer.MAX_VALUE;
    
    /**
     * 線程名稱前綴
     */
    String threadNamePrefix() default "monitored-thread";
    
    /**
     * 是否允許核心線程超時
     */
    boolean allowCoreThreadTimeOut() default false;
    
    /**
     * 線程空閒時間(秒)
     */
    long keepAliveSeconds() default 60;
}

7. 線程池註冊表

package zhangxueliang.monitor.core;

import zhangxueliang.monitor.metrics.ThreadPoolMetrics;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 線程池註冊中心
 */
@Component
public class ThreadPoolRegistry {
    
    private final Map<String, ThreadPoolExecutor> registry = new ConcurrentHashMap<>();
    
    /**
     * 註冊線程池
     */
    public void register(String poolName, ThreadPoolExecutor executor) {
        registry.put(poolName, executor);
    }
    
    /**
     * 獲取線程池
     */
    public ThreadPoolExecutor getThreadPool(String poolName) {
        return registry.get(poolName);
    }
    
    /**
     * 獲取所有線程池
     */
    public Map<String, ThreadPoolExecutor> getAllThreadPools() {
        return new ConcurrentHashMap<>(registry);
    }
    
    /**
     * 獲取所有線程池的監控指標
     */
    public Map<String, ThreadPoolMetrics> getAllMetrics() {
        Map<String, ThreadPoolMetrics> metrics = new ConcurrentHashMap<>();
        registry.forEach((name, executor) -> {
            metrics.put(name, ThreadPoolMetrics.fromExecutor(name, executor));
        });
        return metrics;
    }
    
    /**
     * 獲取指定線程池的監控指標
     */
    public ThreadPoolMetrics getMetrics(String poolName) {
        ThreadPoolExecutor executor = registry.get(poolName);
        return executor != null ? ThreadPoolMetrics.fromExecutor(poolName, executor) : null;
    }
    
    /**
     * 移除線程池
     */
    public void remove(String poolName) {
        registry.remove(poolName);
    }
    
    /**
     * 獲取線程池數量
     */
    public int size() {
        return registry.size();
    }
}

8. 可監控的線程池執行器

package zhangxueliang.monitor.core;

import lombok.extern.slf4j.Slf4j;
import zhangxueliang.monitor.metrics.ThreadPoolMetrics;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 可監控的線程池執行器
 */
@Slf4j
public class MonitorableThreadPoolExecutor extends ThreadPoolExecutor {
    
    // 監控指標
    private final AtomicLong submittedTaskCount = new AtomicLong(0);
    private final AtomicLong completedTaskCount = new AtomicLong(0);
    private final AtomicLong failedTaskCount = new AtomicLong(0);
    private final AtomicLong totalExecutionTime = new AtomicLong(0);
    private final AtomicLong rejectedTaskCount = new AtomicLong(0);
    
    // 線程池名稱
    private final String poolName;
    
    public MonitorableThreadPoolExecutor(String poolName,
                                        int corePoolSize,
                                        int maximumPoolSize,
                                        long keepAliveTime,
                                        TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue,
                                        ThreadFactory threadFactory,
                                        RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 
              threadFactory, new MonitorableRejectedExecutionHandler(handler));
        this.poolName = poolName;
        ((MonitorableRejectedExecutionHandler) getRejectedExecutionHandler())
            .setThreadPool(this);
    }
    
    @Override
    public void execute(Runnable command) {
        submittedTaskCount.incrementAndGet();
        long startTime = System.currentTimeMillis();
        
        super.execute(() -> {
            try {
                command.run();
                completedTaskCount.incrementAndGet();
            } catch (Exception e) {
                failedTaskCount.incrementAndGet();
                log.error("Thread pool [{}] task execution failed", poolName, e);
            } finally {
                long endTime = System.currentTimeMillis();
                totalExecutionTime.addAndGet(endTime - startTime);
            }
        });
    }
    
    @Override
    public <T> Future<T> submit(Callable<T> task) {
        submittedTaskCount.incrementAndGet();
        long startTime = System.currentTimeMillis();
        
        Future<T> future = super.submit(() -> {
            try {
                T result = task.call();
                completedTaskCount.incrementAndGet();
                return result;
            } catch (Exception e) {
                failedTaskCount.incrementAndGet();
                throw e;
            } finally {
                long endTime = System.currentTimeMillis();
                totalExecutionTime.addAndGet(endTime - startTime);
            }
        });
        
        return future;
    }
    
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t != null) {
            failedTaskCount.incrementAndGet();
        }
    }
    
    /**
     * 獲取線程池監控指標
     */
    public ThreadPoolMetrics getMetrics() {
        long submitted = submittedTaskCount.get();
        long completed = completedTaskCount.get();
        long failed = failedTaskCount.get();
        long avgExecutionTime = completed > 0 ? totalExecutionTime.get() / completed : 0;
        
        return ThreadPoolMetrics.builder()
                .poolName(poolName)
                .corePoolSize(getCorePoolSize())
                .maximumPoolSize(getMaximumPoolSize())
                .poolSize(getPoolSize())
                .activeCount(getActiveCount())
                .largestPoolSize(getLargestPoolSize())
                .completedTaskCount(getCompletedTaskCount())
                .taskCount(getTaskCount())
                .queueSize(getQueue().size())
                .queueRemainingCapacity(getQueue().remainingCapacity())
                .submittedTasks(submitted)
                .completedTasks(completed)
                .failedTasks(failed)
                .averageExecutionTime(avgExecutionTime)
                .rejectionCount(rejectedTaskCount.get())
                .isShutdown(isShutdown())
                .isTerminated(isTerminated())
                .build();
    }
    
    /**
     * 增加拒絕任務計數
     */
    public void incrementRejectedCount() {
        rejectedTaskCount.incrementAndGet();
    }
    
    /**
     * 可監控的拒絕執行處理器
     */
    private static class MonitorableRejectedExecutionHandler implements RejectedExecutionHandler {
        private final RejectedExecutionHandler delegate;
        private MonitorableThreadPoolExecutor threadPool;
        
        public MonitorableRejectedExecutionHandler(RejectedExecutionHandler delegate) {
            this.delegate = delegate;
        }
        
        public void setThreadPool(MonitorableThreadPoolExecutor threadPool) {
            this.threadPool = threadPool;
        }
        
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            if (threadPool != null) {
                threadPool.incrementRejectedCount();
            }
            log.warn("Thread pool task rejected, pool: {}, active threads: {}, queue size: {}",
                    threadPool != null ? threadPool.poolName : "unknown",
                    executor.getActiveCount(),
                    executor.getQueue().size());
            
            delegate.rejectedExecution(r, executor);
        }
    }
}

9. 監控指標類

package zhangxueliang.monitor.metrics;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 線程池監控指標
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ThreadPoolMetrics {
    // 基礎信息
    private String poolName;
    private Date timestamp;
    
    // 線程池配置
    private int corePoolSize;
    private int maximumPoolSize;
    
    // 運行狀態
    private int poolSize;
    private int activeCount;
    private int largestPoolSize;
    
    // 任務統計
    private long taskCount;
    private long completedTaskCount;
    private long submittedTasks;
    private long completedTasks;
    private long failedTasks;
    
    // 隊列信息
    private int queueSize;
    private int queueRemainingCapacity;
    
    // 性能指標
    private long averageExecutionTime; // 平均執行時間(ms)
    private long rejectionCount;       // 拒絕次數
    
    // 狀態
    private boolean isShutdown;
    private boolean isTerminated;
    
    /**
     * 從ThreadPoolExecutor創建監控指標
     */
    public static ThreadPoolMetrics fromExecutor(String poolName, ThreadPoolExecutor executor) {
        if (executor instanceof MonitorableThreadPoolExecutor) {
            return ((MonitorableThreadPoolExecutor) executor).getMetrics();
        }
        
        return ThreadPoolMetrics.builder()
                .poolName(poolName)
                .timestamp(new Date())
                .corePoolSize(executor.getCorePoolSize())
                .maximumPoolSize(executor.getMaximumPoolSize())
                .poolSize(executor.getPoolSize())
                .activeCount(executor.getActiveCount())
                .largestPoolSize(executor.getLargestPoolSize())
                .completedTaskCount(executor.getCompletedTaskCount())
                .taskCount(executor.getTaskCount())
                .queueSize(executor.getQueue().size())
                .queueRemainingCapacity(executor.getQueue().remainingCapacity())
                .isShutdown(executor.isShutdown())
                .isTerminated(executor.isTerminated())
                .build();
    }
    
    // 計算指標
    public double getUtilization() {
        return maximumPoolSize > 0 ? (double) activeCount / maximumPoolSize : 0;
    }
    
    public double getQueueUtilization() {
        int capacity = queueSize + queueRemainingCapacity;
        return capacity > 0 ? (double) queueSize / capacity : 0;
    }
    
    public double getSuccessRate() {
        return submittedTasks > 0 ? (double) completedTasks / submittedTasks : 1.0;
    }
    
    public double getFailureRate() {
        return submittedTasks > 0 ? (double) failedTasks / submittedTasks : 0;
    }
}

10. 監控控制器

package zhangxueliang.monitor.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.*;
import zhangxueliang.monitor.core.ThreadPoolRegistry;
import zhangxueliang.monitor.metrics.ThreadPoolMetrics;

import java.util.Map;

/**
 * 線程池監控Web接口
 */
@RestController
@RequestMapping("${threadpool.monitor.endpoint-path:/threadpool/monitor}")
@ConditionalOnProperty(prefix = "threadpool.monitor", name = "webEnabled", havingValue = "true", matchIfMissing = true)
public class ThreadPoolMonitorController {
    
    @Autowired
    private ThreadPoolRegistry registry;
    
    /**
     * 獲取所有線程池的監控數據
     */
    @GetMapping("/metrics")
    public Map<String, ThreadPoolMetrics> getAllMetrics() {
        return registry.getAllMetrics();
    }
    
    /**
     * 獲取指定線程池的監控數據
     */
    @GetMapping("/metrics/{poolName}")
    public ThreadPoolMetrics getMetrics(@PathVariable String poolName) {
        return registry.getMetrics(poolName);
    }
    
    /**
     * 獲取線程池監控摘要
     */
    @GetMapping("/summary")
    public ThreadPoolStatistics getSummary() {
        Map<String, ThreadPoolMetrics> allMetrics = registry.getAllMetrics();
        
        ThreadPoolStatistics statistics = new ThreadPoolStatistics();
        statistics.setPoolCount(allMetrics.size());
        
        long totalActiveThreads = 0;
        long totalQueueSize = 0;
        long totalRejections = 0;
        long totalFailedTasks = 0;
        long totalCompletedTasks = 0;
        
        for (ThreadPoolMetrics metrics : allMetrics.values()) {
            totalActiveThreads += metrics.getActiveCount();
            totalQueueSize += metrics.getQueueSize();
            totalRejections += metrics.getRejectionCount();
            totalFailedTasks += metrics.getFailedTasks();
            totalCompletedTasks += metrics.getCompletedTasks();
        }
        
        statistics.setTotalActiveThreads(totalActiveThreads);
        statistics.setTotalQueueSize(totalQueueSize);
        statistics.setTotalRejections(totalRejections);
        statistics.setTotalFailedTasks(totalFailedTasks);
        statistics.setTotalCompletedTasks(totalCompletedTasks);
        
        return statistics;
    }
    
    /**
     * 獲取線程池列表
     */
    @GetMapping("/pools")
    public Map<String, String> getPoolList() {
        Map<String, ThreadPoolMetrics> allMetrics = registry.getAllMetrics();
        Map<String, String> poolList = new java.util.HashMap<>();
        
        allMetrics.forEach((name, metrics) -> {
            poolList.put(name, String.format("Active: %d, Queue: %d, Rejections: %d",
                    metrics.getActiveCount(), metrics.getQueueSize(), metrics.getRejectionCount()));
        });
        
        return poolList;
    }
}

11. 監控統計類

package zhangxueliang.monitor.web;

import lombok.Data;

/**
 * 線程池監控統計信息
 */
@Data
public class ThreadPoolStatistics {
    private int poolCount;
    private long totalActiveThreads;
    private long totalQueueSize;
    private long totalRejections;
    private long totalFailedTasks;
    private long totalCompletedTasks;
    private long timestamp = System.currentTimeMillis();
}

12. Actuator端點配置

package zhangxueliang.monitor.endpoint;

import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import zhangxueliang.monitor.core.ThreadPoolRegistry;
import zhangxueliang.monitor.metrics.ThreadPoolMetrics;

import java.util.Map;

/**
 * Actuator監控端點
 */
@Component
@Endpoint(id = "${threadpool.monitor.actuator-id:threadpool}")
@ConditionalOnProperty(prefix = "threadpool.monitor", name = "actuatorEnabled", havingValue = "true", matchIfMissing = true)
public class ThreadPoolEndpoint {
    
    private final ThreadPoolRegistry registry;
    
    public ThreadPoolEndpoint(ThreadPoolRegistry registry) {
        this.registry = registry;
    }
    
    @ReadOperation
    public Map<String, ThreadPoolMetrics> metrics() {
        return registry.getAllMetrics();
    }
    
    @ReadOperation
    public Map<String, Object> info() {
        Map<String, ThreadPoolMetrics> metrics = registry.getAllMetrics();
        Map<String, Object> info = new java.util.HashMap<>();
        
        info.put("poolCount", metrics.size());
        
        long totalActive = metrics.values().stream()
                .mapToLong(ThreadPoolMetrics::getActiveCount)
                .sum();
        long totalQueue = metrics.values().stream()
                .mapToLong(ThreadPoolMetrics::getQueueSize)
                .sum();
        long totalRejections = metrics.values().stream()
                .mapToLong(ThreadPoolMetrics::getRejectionCount)
                .sum();
        
        info.put("totalActiveThreads", totalActive);
        info.put("totalQueueSize", totalQueue);
        info.put("totalRejections", totalRejections);
        
        return info;
    }
}

13. AOP切面 - 自動創建監控線程池

package zhangxueliang.monitor.advice;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import zhangxueliang.monitor.annotation.MonitorThreadPool;
import zhangxueliang.monitor.core.MonitorableThreadPoolExecutor;
import zhangxueliang.monitor.core.ThreadPoolRegistry;

import java.lang.reflect.Field;
import java.util.concurrent.*;

/**
 * 監控線程池切面
 */
@Aspect
@Component
@Slf4j
public class ThreadPoolAdvice {
    
    @Autowired
    private ThreadPoolRegistry registry;
    
    /**
     * 攔截@MonitorThreadPool註解的方法
     */
    @Around("@annotation(monitorThreadPool)")
    public Object monitorThreadPool(ProceedingJoinPoint joinPoint, 
                                    MonitorThreadPool monitorThreadPool) throws Throwable {
        // 獲取目標對象
        Object target = joinPoint.getTarget();
        
        // 查找並創建線程池
        String poolName = monitorThreadPool.value();
        if (poolName.isEmpty()) {
            poolName = target.getClass().getSimpleName() + "-ThreadPool";
        }
        
        // 檢查是否已存在線程池
        ThreadPoolExecutor executor = registry.getThreadPool(poolName);
        if (executor == null) {
            executor = createMonitorableThreadPool(poolName, monitorThreadPool);
            registry.register(poolName, executor);
            log.info("Created monitored thread pool: {}", poolName);
        }
        
        // 執行原方法
        return joinPoint.proceed();
    }
    
    /**
     * 創建可監控的線程池
     */
    private MonitorableThreadPoolExecutor createMonitorableThreadPool(
            String poolName, MonitorThreadPool config) {
        
        BlockingQueue<Runnable> workQueue;
        if (config.queueCapacity() == Integer.MAX_VALUE) {
            workQueue = new LinkedBlockingQueue<>();
        } else {
            workQueue = new ArrayBlockingQueue<>(config.queueCapacity());
        }
        
        ThreadFactory threadFactory = new ThreadFactory() {
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName(config.threadNamePrefix() + "-" + threadNumber.getAndIncrement());
                thread.setDaemon(false);
                return thread;
            }
        };
        
        MonitorableThreadPoolExecutor executor = new MonitorableThreadPoolExecutor(
                poolName,
                config.corePoolSize(),
                config.maximumPoolSize(),
                config.keepAliveSeconds(),
                TimeUnit.SECONDS,
                workQueue,
                threadFactory,
                new ThreadPoolExecutor.AbortPolicy()
        );
        
        executor.allowCoreThreadTimeOut(config.allowCoreThreadTimeOut());
        return executor;
    }
}

14. Spring自動配置註冊

# src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  zhangxueliang.monitor.config.ThreadPoolAutoConfig

15. 簡單的Web監控界面

<!-- src/main/resources/static/monitor.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>線程池監控控制枱</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: Arial, sans-serif; background: #f5f5f5; padding: 20px; }
        .container { max-width: 1200px; margin: 0 auto; }
        .header { background: #fff; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .header h1 { color: #333; margin-bottom: 10px; }
        .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 20px; }
        .stat-card { background: #fff; padding: 15px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .stat-card h3 { color: #666; font-size: 14px; margin-bottom: 10px; }
        .stat-card .value { font-size: 24px; font-weight: bold; color: #1890ff; }
        .pools { background: #fff; border-radius: 8px; padding: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .pools h2 { margin-bottom: 20px; color: #333; }
        .pool-table { width: 100%; border-collapse: collapse; }
        .pool-table th, .pool-table td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #eee; }
        .pool-table th { background: #fafafa; font-weight: bold; color: #666; }
        .pool-table tr:hover { background: #f9f9f9; }
        .status-good { color: #52c41a; }
        .status-warning { color: #faad14; }
        .status-danger { color: #f5222d; }
        .refresh-btn { background: #1890ff; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; }
        .refresh-btn:hover { background: #40a9ff; }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🚀 線程池監控控制枱</h1>
            <p>實時監控應用程序中的線程池運行狀態</p>
            <button class="refresh-btn" onclick="loadData()">刷新數據</button>
        </div>
        
        <div class="stats" id="stats"></div>
        
        <div class="pools">
            <h2>線程池詳情</h2>
            <table class="pool-table" id="poolTable">
                <thead>
                    <tr>
                        <th>線程池名稱</th>
                        <th>核心線程數</th>
                        <th>最大線程數</th>
                        <th>活躍線程</th>
                        <th>隊列大小</th>
                        <th>任務總數</th>
                        <th>拒絕次數</th>
                        <th>狀態</th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </div>
    </div>

    <script>
        // 加載監控數據
        async function loadData() {
            try {
                // 加載統計數據
                const summaryRes = await fetch('/threadpool/monitor/summary');
                const summary = await summaryRes.json();
                
                // 更新統計卡片
                document.getElementById('stats').innerHTML = `
                    <div class="stat-card">
                        <h3>線程池總數</h3>
                        <div class="value">${summary.poolCount}</div>
                    </div>
                    <div class="stat-card">
                        <h3>活躍線程數</h3>
                        <div class="value">${summary.totalActiveThreads}</div>
                    </div>
                    <div class="stat-card">
                        <h3>隊列任務數</h3>
                        <div class="value">${summary.totalQueueSize}</div>
                    </div>
                    <div class="stat-card">
                        <h3>拒絕任務數</h3>
                        <div class="value">${summary.totalRejections}</div>
                    </div>
                `;
                
                // 加載線程池詳情
                const metricsRes = await fetch('/threadpool/monitor/metrics');
                const metrics = await metricsRes.json();
                
                // 更新表格
                const tbody = document.querySelector('#poolTable tbody');
                tbody.innerHTML = '';
                
                for (const [name, data] of Object.entries(metrics)) {
                    const utilization = data.activeCount / data.maximumPoolSize;
                    let statusClass = 'status-good';
                    if (utilization > 0.8) statusClass = 'status-warning';
                    if (utilization > 0.95) statusClass = 'status-danger';
                    
                    const row = document.createElement('tr');
                    row.innerHTML = `
                        <td><strong>${name}</strong></td>
                        <td>${data.corePoolSize}</td>
                        <td>${data.maximumPoolSize}</td>
                        <td class="${statusClass}">${data.activeCount}</td>
                        <td>${data.queueSize}/${data.queueSize + data.queueRemainingCapacity}</td>
                        <td>${data.taskCount}</td>
                        <td>${data.rejectionCount}</td>
                        <td class="${statusClass}">${data.isShutdown ? '已關閉' : '運行中'}</td>
                    `;
                    tbody.appendChild(row);
                }
            } catch (error) {
                console.error('加載監控數據失敗:', error);
                alert('加載監控數據失敗,請檢查服務是否正常');
            }
        }
        
        // 頁面加載時自動加載數據
        document.addEventListener('DOMContentLoaded', loadData);
        
        // 每5秒自動刷新
        setInterval(loadData, 5000);
    </script>
</body>
</html>

16. 使用説明文檔

創建 README.md 文件:

# ThreadPool Monitor

Spring Boot 線程池監控組件

## 功能特性

- ✅ 自動監控線程池運行狀態
- ✅ 提供RESTful API監控接口
- ✅ 集成Spring Boot Actuator
- ✅ 提供Web監控控制枱
- ✅ 支持線程池創建註解
- ✅ 實時收集監控指標
- ✅ 支持告警閾值配置

## 快速開始

### 1. 添加依賴

在Spring Boot項目中添加依賴:

```xml
<dependency>
    <groupId>zhangxueliang</groupId>
    <artifactId>threadpool-monitor</artifactId>
    <version>1.0.0</version>
</dependency>

2. 啓用監控

在Spring Boot啓動類上添加註解:

@SpringBootApplication
@EnableThreadPoolMonitor
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3. 配置參數(可選)

threadpool:
  monitor:
    enabled: true
    endpoint-path: /threadpool/monitor
    web-path: /threadpool/console
    actuator-enabled: true
    refresh-interval: 5000
    alert:
      queue-usage-threshold: 80
      active-thread-threshold: 80
      rejection-threshold: 10

4. 使用監控註解

@Service
public class OrderService {
    
    @MonitorThreadPool(
        value = "order-process-pool",
        corePoolSize = 5,
        maximumPoolSize = 10,
        queueCapacity = 100,
        threadNamePrefix = "order-thread"
    )
    public void processOrder(Order order) {
        // 業務邏輯
    }
}

監控接口

REST API

  • GET /threadpool/monitor/metrics - 獲取所有線程池指標
  • GET /threadpool/monitor/metrics/{poolName} - 獲取指定線程池指標
  • GET /threadpool/monitor/summary - 獲取監控摘要
  • GET /threadpool/monitor/pools - 獲取線程池列表

Actuator端點

  • GET /actuator/threadpool - 獲取監控數據
  • GET /actuator/threadpool/info - 獲取監控信息

Web控制枱

訪問 http://localhost:8080/threadpool/console 查看監控界面

監控指標

  • 線程池配置:核心線程數、最大線程數
  • 運行狀態:活躍線程數、池大小、隊列大小
  • 任務統計:提交任務數、完成任務數、失敗任務數
  • 性能指標:平均執行時間、拒絕次數
  • 狀態信息:是否關閉、是否終止

構建部署

# 打包
mvn clean package

# 安裝到本地倉庫
mvn clean install

# 部署到私有倉庫
mvn clean deploy

注意事項

  1. 確保Spring Boot版本為2.0.6.RELEASE
  2. 默認監控端口為8080,可通過server.port修改
  3. 監控數據每5秒刷新一次
  4. 線程池創建後會自動註冊到監控中心
## 17. 打包和發佈

### 打包JAR:

```bash
mvn clean package

安裝到本地倉庫:

mvn clean install

在其他Spring Boot項目中使用:

  1. 添加依賴
<dependency>
    <groupId>zhangxueliang</groupId>
    <artifactId>threadpool-monitor</artifactId>
    <version>1.0.0</version>
</dependency>
  1. 啓用監控
@SpringBootApplication
@EnableThreadPoolMonitor
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
  1. 訪問監控
  • Web控制枱:http://localhost:8080/threadpool/console
  • API接口:http://localhost:8080/threadpool/monitor/metrics
  • Actuator端點:http://localhost:8080/actuator/threadpool

特點總結

  1. 開箱即用:只需添加註解即可啓用完整監控功能
  2. 零代碼侵入:通過註解和AOP實現,不影響業務代碼
  3. 全面監控:覆蓋線程池所有關鍵指標
  4. 多接口支持:提供REST API、Actuator端點、Web控制枱
  5. 易於集成:與Spring Boot 2.0.6完美兼容
  6. 配置靈活:支持豐富的配置選項
  7. 獨立JAR:不依賴外部組件,打包即用