加固exit退出流程。

This commit is contained in:
2026-01-15 19:32:38 +08:00
parent 23c73a5ef4
commit 098b9887e2
3 changed files with 121 additions and 35 deletions

View File

@@ -1,14 +1,23 @@
#!/bin/bash
# 1. 先跳转到脚本所在目录,再定位项目根目录(核心修复)
cd "$(dirname "${BASH_SOURCE[0]}")"
BASE_DIR=$(cd .. && pwd) # 从bash目录向上跳1级得到项目根目录
# Termux专属启动脚本 编译+启动 解决exit后卡空行/需手动^C问题
cd "$(dirname "${BASH_SOURCE[0]}")" || { echo "目录切换失败"; exit 1; }
BASE_DIR=$(cd .. && pwd)
# 2. 执行编译用绝对路径调用build_class.sh避免路径问题
bash "$BASE_DIR/bash/build_class.sh"
# 1. 编译校验
BUILD_SH="$BASE_DIR/bash/build_class.sh"
bash "$BUILD_SH" || { echo "编译失败退出"; exit 1; }
# 3. 配置类路径指向根目录的runtime和libs
CLASSPATH="$BASE_DIR/runtime:$BASE_DIR/libs/*"
# 2. 类路径配置
CLASSPATH="$BASE_DIR/runtime"
[ -d "$BASE_DIR/libs" ] && CLASSPATH="$CLASSPATH:$BASE_DIR/libs/*"
MAIN_CLASS="Main"
echo "正在启动 Main 类,类路径:$CLASSPATH"
java -cp "$CLASSPATH" $MAIN_CLASS
# 3. 关键修复:预重置终端+进程绑定+退出后强制清流
stty -echoctl # 屏蔽^C视觉印记
echo -e "\n🚀 服务启动中输入help查指令输入exit优雅停机"
# 启动并绑定进程Java结束脚本立刻走后续逻辑
java -cp "$CLASSPATH" "$MAIN_CLASS"
# Java退出后 强制重置终端+脚本退出,彻底无残留
stty sane
exit $?

View File

@@ -13,7 +13,7 @@ import java.io.IOException;
* 支持控制台输入交互输入help查帮助、输入exit退出、其他指令提示未识别
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @Date 2026/01/14 00:00:00
* @LastEditTime 2026/01/16 22:38:00
* @LastEditTime 2026/01/17 10:10:00
*/
public class Main {
// 全局静态属性(常量→变量,顺序清晰)
@@ -40,6 +40,8 @@ public class Main {
ConsoleInputUtils.initConsoleScanner();
consoleBlockForService();
// 适配加固:退出循环后,兜底释放所有资源,形成闭环
releaseAllResources();
LogUtils.i(TAG, "【函数结束】main(),程序正常退出");
}
@@ -149,6 +151,9 @@ public class Main {
String errMsg = "HTTP服务启动失败端口 " + httpPort + " 可能被占用";
System.err.println(errMsg);
LogUtils.e(TAG, "【函数异常】startAuthCenterHttpService()HTTP服务启动失败", e);
// 启动失败时,兜底释放已初始化资源,避免残留
ConsoleInputUtils.forceExit();
releaseAllResources();
System.exit(1);
}
LogUtils.d(TAG, "【函数结束】startAuthCenterHttpService()HTTP服务启动流程执行完成");
@@ -164,6 +169,8 @@ public class Main {
@Override
public void run() {
LogUtils.i(TAG, "收到服务停止信号,执行优雅停机流程");
// 适配加固:优先调用强制退出,确保状态同步
ConsoleInputUtils.forceExit();
ConsoleInputUtils.closeConsoleScanner();
if (httpService != null && httpService.isRunning()) {
httpService.stop();
@@ -176,13 +183,14 @@ public class Main {
// 低功耗无限阻塞,根据指令状态判断是否退出循环
while (true) {
try {
// 检查指令若触发exit则跳出循环
if (ConsoleInputUtils.checkConsoleCommand()) {
// 适配加固:优先判断退出标识,减少无效调用,提速退出响应
if (ConsoleInputUtils.isExit() || ConsoleInputUtils.checkConsoleCommand()) {
break;
}
Thread.sleep(500);
} catch (InterruptedException e) {
LogUtils.w(TAG, "【阻塞中断】服务阻塞线程被中断,准备退出循环", e);
ConsoleInputUtils.forceExit();
ConsoleInputUtils.closeConsoleScanner();
Thread.currentThread().interrupt();
break;
@@ -191,6 +199,21 @@ public class Main {
LogUtils.d(TAG, "【函数结束】consoleBlockForService(),常驻阻塞流程退出");
}
/**
* 兜底释放所有资源,适配加固后工具类,形成退出闭环(核心适配点)
*/
private static void releaseAllResources() {
LogUtils.d(TAG, "【函数调用】releaseAllResources(),兜底释放所有服务资源");
// 1. 停止HTTP服务
if (httpService != null && httpService.isRunning()) {
httpService.stop();
LogUtils.i(TAG, "HTTP服务兜底停止完成");
}
// 2. 关闭控制台扫描器彻底释放终端输入流解决Termux阻塞关键
ConsoleInputUtils.closeConsoleScanner();
LogUtils.d(TAG, "【函数结束】releaseAllResources(),所有资源释放完成");
}
/**
* 数组转字符串Java7兼容替代String.join适配参数日志输出
* @param arr 目标字符串数组

View File

@@ -9,44 +9,73 @@ import java.util.Scanner;
* 支持help查看帮助、exit退出服务预留指令扩展入口
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @Date 2026/01/14 00:00:00
* @LastEditTime 2026/01/16 22:38:00
* @LastEditTime 2026/01/17 10:00:00
*/
public class ConsoleInputUtils {
private static final String TAG = "ConsoleInputUtils";
public static final String CMD_HELP = "help";
public static final String CMD_EXIT = "exit";
private static Scanner scanner;
// 退出标识,控制服务常驻循环
private static boolean isExit = false;
private static volatile boolean isExit = false; // 线程安全,防止多线程并发问题
private static boolean isScannerInit = false; // 扫描器初始化标识,避免重复创建/关闭
/**
* 初始化控制台扫描器,提示支持的核心指令
* 初始化控制台扫描器,支持重复调用(防重复初始化)
*/
public static void initConsoleScanner() {
if (isScannerInit || scanner != null) {
LogUtils.d(TAG, "【函数调用】initConsoleScanner(),扫描器已初始化,无需重复执行");
return;
}
LogUtils.d(TAG, "【函数调用】initConsoleScanner(),初始化控制台输入监听");
scanner = new Scanner(System.in);
System.out.println("\n💡 输入 " + CMD_HELP + " 查看帮助,输入 " + CMD_EXIT + " 退出服务");
LogUtils.d(TAG, "【函数结束】initConsoleScanner(),控制台输入扫描器初始化完成");
try {
scanner = new Scanner(System.in);
isScannerInit = true;
System.out.println("\n💡 输入 " + CMD_HELP + " 查看帮助,输入 " + CMD_EXIT + " 退出服务");
LogUtils.d(TAG, "【函数结束】initConsoleScanner(),控制台输入扫描器初始化完成");
} catch (Exception e) {
LogUtils.e(TAG, "【函数异常】initConsoleScanner(),扫描器初始化失败", e);
isScannerInit = false;
}
}
/**
* 检查控制台输入指令,分发到对应功能逻辑
* 检查控制台输入指令,分发到对应功能逻辑(非阻塞优化+异常兜底)
* @return true=需退出服务false=继续常驻
*/
public static boolean checkConsoleCommand() {
if (scanner == null || !scanner.hasNextLine()) {
// 退出标识优先,直接返回,避免无效执行
if (isExit) {
return true;
}
// 扫描器未初始化/已关闭,直接返回,防止空指针
if (!isScannerInit || scanner == null) {
return isExit;
}
String input = scanner.nextLine().trim();
LogUtils.d(TAG, "检测到控制台输入指令:" + input);
// 指令分发逻辑
if (CMD_HELP.equalsIgnoreCase(input)) {
handleHelpCmd();
} else if (CMD_EXIT.equalsIgnoreCase(input)) {
handleExitCmd();
} else if (!input.isEmpty()) {
handleCustomCmd(input);
try {
// 非阻塞检查无输入直接返回降低CPU占用+避免流阻塞
if (!scanner.hasNextLine()) {
return isExit;
}
String input = scanner.nextLine().trim();
LogUtils.d(TAG, "检测到控制台输入指令:" + input);
// 指令分发逻辑
if (CMD_HELP.equalsIgnoreCase(input)) {
handleHelpCmd();
} else if (CMD_EXIT.equalsIgnoreCase(input)) {
handleExitCmd();
} else if (!input.isEmpty()) {
handleCustomCmd(input);
}
} catch (IllegalStateException e) {
// 捕获扫描器已关闭异常避免Termux环境下报错
LogUtils.w(TAG, "【指令检查】扫描器已关闭,停止输入监听", e);
isExit = true;
} catch (Exception e) {
LogUtils.e(TAG, "【指令检查】输入监听异常,终止服务", e);
isExit = true;
}
return isExit;
}
@@ -56,16 +85,25 @@ public class ConsoleInputUtils {
*/
private static void handleHelpCmd() {
LogUtils.d(TAG, "【指令处理】执行help指令展示服务帮助信息");
HelpInfoUtils.printFullHelpInfo();
try {
HelpInfoUtils.printFullHelpInfo();
} catch (Exception e) {
LogUtils.e(TAG, "【指令异常】展示帮助信息失败", e);
System.out.println("⚠️ 帮助信息展示异常,请手动核对指令");
}
}
/**
* 处理exit指令标记退出状态,触发优雅停机
* 处理exit指令强制退出闭环,提前释放资源,杜绝终端阻塞
*/
private static void handleExitCmd() {
LogUtils.d(TAG, "【指令处理】执行exit指令标记服务退出状态");
isExit = true;
System.out.println("\n📢 已接收退出指令,正在执行优雅停机...");
// 核心加固提前关闭扫描器释放终端输入流解决Termux阻塞关键
closeConsoleScanner();
// 主动刷新输出流,确保提示语正常打印
System.out.flush();
}
/**
@@ -78,12 +116,19 @@ public class ConsoleInputUtils {
}
/**
* 关闭控制台扫描器,释放系统资源
* 关闭控制台扫描器,双重保障+状态重置,彻底释放资源
*/
public static void closeConsoleScanner() {
if (scanner != null) {
scanner.close();
LogUtils.d(TAG, "控制台输入扫描器已关闭,资源释放完成");
try {
scanner.close();
LogUtils.d(TAG, "控制台输入扫描器已关闭,资源释放完成");
} catch (Exception e) {
LogUtils.w(TAG, "关闭扫描器时出现异常", e);
} finally {
scanner = null; // 置空,杜绝重复关闭
isScannerInit = false; // 重置初始化标识
}
}
}
@@ -94,5 +139,14 @@ public class ConsoleInputUtils {
public static boolean isExit() {
return isExit;
}
/**
* 强制退出(兜底方法,供外部紧急调用)
*/
public static void forceExit() {
LogUtils.w(TAG, "【紧急处理】执行强制退出流程");
isExit = true;
closeConsoleScanner();
}
}