首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實現 Windows 定時關機服務:從代碼到系統服務註冊全流程

     編輯:Java 相關知識

業務場景

在受控電腦上部署後台服務,工作日 17:00–23:25 允許使用,超時強制關機;防止用戶修改系統時間繞過限制;以 Windows Service 形式運行,無界面、難被終止。

架構設計


┌─────────────────────────────────────┐
│      Windows Service Manager        │
│  (JavaService / Procrun / WinSW)    │
└──────────────┬──────────────────────┘
               │ 啟動 JVM
               ▼
┌─────────────────────────────────────┐
│  TimerShutDownWindows (主類)         │
│  ├─ TimerDetector (監控線程)         │
│  │   ├─ 校驗系統時間是否被竄改        │
│  │   ├─ 判斷是否達到關機窗口         │
│  │   └─ 執行 shutdown 命令           │
│  └─ 日誌輸出                         │
└─────────────────────────────────────┘

核心監控邏輯


public class TimerShutDownWindows {
    // 配置常量
    private static final long DETECT_INTERVAL_MS = 5_000;
    private static final int ALLOW_START_HOUR = 17;   // 17:00
    private static final int ALLOW_END_HOUR = 23;     // 23:25
    private static final int ALLOW_END_MINUTE = 25;
    private static final String LOG_FILE = "D:/my_shutdown.log";

    private static long lastCheckMs = 0;
    private static boolean hasShutdown = false;

    public static void main(String[] args) {
        new Thread(new TimerDetector(), "Shutdown-Detector").start();
    }

    static class TimerDetector implements Runnable {
        private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        private PrintWriter log;

        @Override public void run() {
            initLog();
            log("服務啟動:" + sdf.format(new Date()));

            while (true) {
                if (shouldForceShutdown()) {
                    executeShutdown();
                } else {
                    hasShutdown = false;
                }
                sleepQuietly(DETECT_INTERVAL_MS);
            }
        }

        private boolean shouldForceShutdown() {
            // 1. 檢測系統時間被竄改
            if (detectTimeTampering()) return true;

            // 2. 正常時間窗口判斷
            Calendar now = Calendar.getInstance();
            int hour = now.get(Calendar.HOUR_OF_DAY);
            int minute = now.get(Calendar.MINUTE);

            if (hour < ALLOW_START_HOUR) return true;           // 17點前
            if (hour > ALLOW_END_HOUR) return true;             // 23點後
            if (hour == ALLOW_END_HOUR && minute >= ALLOW_END_MINUTE) return true; // 23:25 後
            return false;
        }

        private boolean detectTimeTampering() {
            long now = System.currentTimeMillis();
            if (lastCheckMs == 0) {
                lastCheckMs = now;
                return false;
            }
            long diff = Math.abs(now - lastCheckMs);
            long maxAllowed = DETECT_INTERVAL_MS + 60_000; // 允許 1 分鐘誤差
            log("時間差:" + diff + "ms,閾值:" + maxAllowed + "ms");
            if (diff > maxAllowed) return true;  // 系統時間被修改
            lastCheckMs = now;
            return false;
        }

        private void executeShutdown() {
            if (hasShutdown) return;
            log("觸發強制關機,時間:" + sdf.format(new Date()));
            try {
                // /s 關機 /t 120 120秒倒計時 /c 提示信息
                Runtime.getRuntime().exec("shutdown -s -t 120 -c \"超時使用,2分鐘後自動關機\"");
            } catch (IOException e) {
                log("關機命令失敗:" + e.getMessage());
            }
            hasShutdown = true;
        }

        private void initLog() {
            try {
                log = new PrintWriter(new FileWriter(LOG_FILE, true), true);
            } catch (IOException e) {
                log = new PrintWriter(System.out);
            }
        }
        private void log(String msg) { if (log != null) log.println(msg); }
        private void sleepQuietly(long ms) {
            try { Thread.sleep(ms); } catch (InterruptedException ignored) {}
        }
    }
}

註冊為 Windows 服務:三種主流方案

工具優點缺點適用場景
WinSW (推薦)單一 .exe、XML 配置、支持 .NET/Java、GitHub 熱門需 .NET Runtime現代部署、CI/CD 友好
Procrun (Apache Commons Daemon)純原生、Tomcat 官方用、成熟穩定配置繁瑣、需安裝 prunsrv.exe生產環境標準化
JavaService (文中原方案)老牌、輕量停止維護、僅 32 位、JDK 9+ 不兼容維護舊系統

WinSW 快速上手

  1. 下載 WinSW.NET4.exe 重命名為 ShutdownService.exe
  2. 同目錄建立 ShutdownService.xml:
    
    
      AutoShutdown
      Auto Shutdown Service
      定時關機監控服務
      java
      -cp "D:/app/shutdown.jar" com.example.TimerShutDownWindows
      rotate
      
      Automatic
    
    
  3. 管理員 CMD 執行:
    
    ShutdownService.exe install
    ShutdownService.exe start
    

服務管理命令


net start AutoShutdown     # 啟動
net stop AutoShutdown      # 停止
sc delete AutoShutdown     # 刪除服務

安全加固建議

  • 服務以 **普通用戶** 運行(非 SYSTEM),限制權限
  • 日誌文件 ACL 限制寫入
  • 關機命令改用 shutdown /s /f /t 0 強制立即關機,防止應用攔截
  • 關鍵配置(允許時間窗口)外置到加密配置文件或註冊表,防篡改

總結

Java + WinSW 實現 Windows 定時關機服務,核心在於:獨立監控線程 + 時間竄改檢測 + 系統級關機命令 + 服務化部署。代碼量小、邏輯清晰,適合學校機房、企業終端管控等場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved