192.168.9.165 недель назад: 2
Родитель
Сommit
2188917c73

+ 75 - 42
src/main/java/com/fdkankan/fusion/AppListener.java

@@ -1,9 +1,5 @@
 package com.fdkankan.fusion;
 
-
-import cn.hutool.core.date.DateUnit;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.system.SystemUtil;
 import com.fdkankan.fusion.config.CacheUtil;
 import com.fdkankan.redis.util.RedisUtil;
@@ -12,8 +8,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.ApplicationArguments;
 import org.springframework.boot.ApplicationRunner;
 import org.springframework.boot.SpringApplication;
+import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.stereotype.Component;
-import org.springframework.web.context.WebApplicationContext;
 
 import javax.annotation.Resource;
 import java.io.BufferedReader;
@@ -24,69 +20,102 @@ import java.io.InputStreamReader;
 public class AppListener implements ApplicationRunner {
 
     @Resource
-    private WebApplicationContext applicationContext;
+    private ConfigurableApplicationContext applicationContext;
+
     @Autowired
     private RedisUtil redisUtil;
+
     @Override
     public void run(ApplicationArguments args) {
-        if (CacheUtil.settingEntity.getPid()<= 0) {
-           log.info("未配置 app.monitorPid,跳过 PID 监听。");
+        long pid = CacheUtil.settingEntity.getPid();
+        if (pid <= 0) {
+            log.info("未配置 app.monitorPid,跳过 PID 监听。");
             return;
         }
 
-        log.info("启动监听 PID: " + CacheUtil.settingEntity.getPid());
-
-        Thread monitorThread = new Thread(() -> {
-            while (true) {
-                try {
-                    if (!isProcessAlive(CacheUtil.settingEntity.getPid())) {
-                        log.info("目标 PID 不存在,准备退出 SpringBoot 服务...");
-                        shutdownApplication();
-                        break;
-                    }
-                    if (redisUtil.hasKey("QUIT_JOB_FUSION")) {
-                        log.info("收到推出通知,准备退出 SpringBoot 服务...");
-                        redisUtil.del("QUIT_JOB_FUSION");
-                        shutdownApplication();
-                        break;
-                    }
-                    Thread.sleep(2000);
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        });
+        log.info("启动监听 PID: {}", pid);
 
+        Thread monitorThread = new Thread(() -> monitorLoop(pid), "fusion-pid-monitor-thread");
         monitorThread.setDaemon(true);
         monitorThread.start();
     }
 
     /**
+     * 监控循环:
+     * 1. 监听 Redis 中的 QUIT_JOB_FUSION
+     * 2. 检测目标 PID 是否存活
+     * 任一条件触发则优雅关闭应用
+     */
+    private void monitorLoop(long pid) {
+        while (!Thread.currentThread().isInterrupted()) {
+            try {
+                // 退出通知优先
+                if (redisUtil.hasKey("QUIT_JOB_FUSION")) {
+                    log.info("收到退出通知,准备退出 SpringBoot 服务...");
+                    redisUtil.del("QUIT_JOB_FUSION");
+                    shutdownApplication();
+                    break;
+                }
+
+                // 检测 PID
+                if (!isProcessAlive(pid)) {
+                    log.info("目标 PID 不存在,准备退出 SpringBoot 服务... pid={}", pid);
+                    shutdownApplication();
+                    break;
+                }
+
+            } catch (Exception e) {
+                log.error("PID 监听线程异常", e);
+            }
+
+            // 防忙等,无论是否异常都休眠
+            try {
+                Thread.sleep(2000L);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                log.warn("PID 监听线程被中断,停止监听。");
+                break;
+            }
+        }
+    }
+
+    /**
      * 判断 PID 是否存活 (Java 8 版本,使用系统命令)
      */
     private boolean isProcessAlive(long pid) {
+        String pidStr = String.valueOf(pid);
         try {
+            // 防御:PID 必须为纯数字
+            if (!pidStr.matches("\\d+")) {
+                log.error("非法 PID: {}", pidStr);
+                return false;
+            }
+
             if (SystemUtil.getOsInfo().isWindows()) {
-                // Windows 使用 tasklist
-                Process process = Runtime.getRuntime().exec("tasklist /FI \"PID eq " + pid + "\"");
-                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
-                    String line;
-                    while ((line = reader.readLine()) != null) {
-                        if (line.contains(String.valueOf(pid))) {
-                            return true;
-                        }
-                    }
-                }
+                // PowerShell 命令:Get-Process -Id PID
+                Process process = new ProcessBuilder(
+                        "powershell",
+                        "-Command",
+                        "Get-Process -Id " + pidStr + " | Out-Null"
+                ).redirectErrorStream(true).start();
+
+                int exitCode = process.waitFor();
+
+                // exitCode == 0 → 进程存在
+                // exitCode != 0 → 进程不存在
+                return exitCode == 0;
             } else {
                 // Linux / Mac 使用 kill -0
-                Process process = Runtime.getRuntime().exec("kill -0 " + pid);
+                Process process = new ProcessBuilder("kill", "-0", pidStr)
+                        .redirectErrorStream(true)
+                        .start();
                 int exitCode = process.waitFor();
                 return exitCode == 0;
             }
         } catch (Exception e) {
+            log.error("检查进程存活状态失败,pid={}", pidStr, e);
             return false;
         }
-        return false;
     }
 
     /**
@@ -94,8 +123,12 @@ public class AppListener implements ApplicationRunner {
      */
     private void shutdownApplication() {
         try {
+            log.info("准备退出 SpringBoot 服务...shutdownApplication");
             SpringApplication.exit(applicationContext, () -> 0);
+        } catch (Exception e) {
+            log.error("关闭 Spring Boot 应用时发生异常", e);
         } finally {
+            log.info("退出 JVM");
             System.exit(0);
         }
     }

+ 1 - 1
src/main/java/com/fdkankan/fusion/task/InitService.java

@@ -53,10 +53,10 @@ public class InitService {
         initConfig();
         //checkDefaultImag();
         //delMediaLibrary();
-        writerStateFile();
         delRedisKey();
         cleanRedisKey();
         updateHotIcon();
+        writerStateFile();
     }