如何让Java程序退出后仍保持Windows服务运行,并在后续通过Java程序停止该服务?
如何让Java程序退出后仍保持Windows服务运行,并在后续通过Java程序停止该服务?
问题核心原因
你的启动命令存在关键错误:你用自己的test.exe(Socket服务器)来执行sc start命令,但test.exe并不是Windows的命令行工具cmd.exe,这导致你实际上是直接运行了test.exe作为Java的子进程,而非通过Windows服务控制管理器(SCM)启动服务。这种情况下,test.exe和Java进程存在父子关联,Java退出后它也会跟着停止。
解决方案步骤
1. 修正启动/停止命令,使用系统自带的sc.exe
Windows自带的sc.exe是专门用于管理服务的工具,通过它向SCM发送启动/停止指令,SCM会独立管理服务进程,和Java进程完全解耦,Java退出后服务会继续运行。
2. 正确处理外部命令的IO流
Java执行外部命令时,如果不处理子进程的输入/错误流,缓冲区满会导致子进程阻塞,进而影响命令的正常执行。
具体代码实现
启动服务的正确代码
// 调用Windows系统服务控制工具sc.exe启动服务 String[] startScript = { "C:\\Windows\\System32\\sc.exe", "start", "Test" // 你的服务名称 }; Process process = Runtime.getRuntime().exec(startScript); // 处理子进程的标准输出(避免缓冲区阻塞) new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { // 可选:记录启动日志 // System.out.println("服务启动日志:" + line); } } catch (IOException e) { e.printStackTrace(); } }).start(); // 处理子进程的错误输出 new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { String line; while ((line = reader.readLine()) != null) { System.err.println("服务启动错误:" + line); } } catch (IOException e) { e.printStackTrace(); } }).start(); // 等待命令执行完成,检查退出码 int exitCode = process.waitFor(); if (exitCode == 0) { System.out.println("服务启动指令已成功提交给SCM"); } else { System.err.println("服务启动指令提交失败,退出码:" + exitCode); }
停止服务的正确代码
// 调用sc.exe停止服务 String[] stopScript = { "C:\\Windows\\System32\\sc.exe", "stop", "Test" // 你的服务名称 }; Process stopProcess = Runtime.getRuntime().exec(stopScript); // 同样处理IO流,避免阻塞 new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(stopProcess.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { // 可选:记录停止日志 // System.out.println("服务停止日志:" + line); } } catch (IOException e) { e.printStackTrace(); } }).start(); new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(stopProcess.getErrorStream()))) { String line; while ((line = reader.readLine()) != null) { System.err.println("服务停止错误:" + line); } } catch (IOException e) { e.printStackTrace(); } }).start(); int stopExitCode = stopProcess.waitFor(); if (stopExitCode == 0) { System.out.println("服务停止指令已成功提交给SCM"); } else { System.err.println("服务停止指令提交失败,退出码:" + stopExitCode); }
额外验证步骤
确保你的服务本身能独立运行:
- 以管理员身份打开命令提示符,执行
sc start Test - 关闭命令提示符,打开服务管理器(
services.msc)或任务管理器,检查Test服务是否持续运行 - 如果手动启动后服务也会停止,说明你的
test.exe可能没有正确实现Windows服务的接口:- 如果你用工具(如NSSM、WinSW)包装控制台程序为服务,请检查工具的配置是否正确
- 如果是自行开发的服务程序,请确保它正确处理SCM的服务控制请求(如调用
RegisterServiceCtrlHandler等API)
备注:内容来源于stack exchange,提问作者defa0009
相关产品推荐
相关产品推荐

