Skip to content

Commit 39ab152

Browse files
committed
[fit-launcher] 使用 Node.js 重写启动脚本,实现真正的跨平台支持
主要改进: 1. 启动脚本重构 - 使用 Node.js 重写核心启动逻辑 (fit.js) - Unix/Linux/macOS 使用 fit 脚本(Node.js 实现) - Windows 使用 fit.cmd 批处理文件 - 移除旧的 fit.bat 文件 2. 跨平台兼容性 - 解决 Bash 脚本在不同系统上的兼容性问题 - 避免 macOS 上 readlink -f 不可用的问题 - 统一 Windows/Linux/macOS 的使用体验 3. 功能增强 - 改进错误处理和错误信息输出 - 正确处理进程信号 (SIGINT/SIGTERM) - 更清晰的参数解析逻辑 - 更好的代码可维护性 4. 文档更新 - 重构模块 README,从模块级别进行说明 - 添加架构设计、启动流程等技术文档 - 完善使用说明和故障排除指南 技术栈:Node.js 12+ 命令接口保持完全兼容,无需修改现有文档和脚本
1 parent 8186b7d commit 39ab152

File tree

5 files changed

+456
-85
lines changed

5 files changed

+456
-85
lines changed
Lines changed: 287 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,296 @@
1-
<div style="text-align: center;"><span style="font-size: 40px"><b>常规FIT应用启动程序</b></span></div>
1+
# FIT Discrete Launcher(FIT 离散启动器)
22

3-
[TOC]
3+
## 模块概述
44

5-
# 说明
5+
`fit-discrete-launcher` 是 FIT 框架的应用启动入口模块,提供了完整的应用程序启动、类加载和进程管理能力。该模块支持 FIT 应用以离散(独立进程)模式运行,是 FIT 框架"聚散部署"能力的核心实现之一。
66

7-
在常规FIT应用中,以目录展开形式被安装在OS中,通过在环境变量中配置`FIT_HOME`来指定应用程序所在根目录。
7+
**主要职责:**
8+
- 应用程序的启动引导
9+
- 自定义类加载器体系的初始化
10+
- 跨平台启动脚本的提供
11+
- 应用程序的生命周期管理
812

9-
应用程序可通过FIT提供的启动脚本,通过相应命令启动应用程序。
13+
## 核心特性
1014

11-
# 运行时目录结构
15+
### 1. 离散启动能力
1216

13-
![avatar](https://cloudmodelingapi.tools.huawei.com/cloudmodelingdrawiosvr/d/2Fay)
17+
支持 FIT 应用以独立进程的方式启动和运行:
18+
- 每个应用拥有独立的 JVM 进程
19+
- 完全隔离的运行环境
20+
- 支持多应用并行部署
1421

15-
# ClassLoader模型
22+
### 2. 自定义类加载体系
1623

17-
![avatar](https://cloudmodelingapi.tools.huawei.com/cloudmodelingdrawiosvr/d/2FfL)
24+
实现了分层的类加载器架构:
25+
- **SharedClassLoader**: 加载共享类库
26+
- **FrameworkClassLoader**: 加载框架核心类
27+
- 支持插件化的类隔离机制
1828

29+
### 3. 跨平台启动脚本
30+
31+
提供基于 Node.js 的跨平台启动脚本:
32+
- Unix/Linux/macOS: `fit` 脚本
33+
- Windows: `fit.cmd` 批处理文件
34+
- 统一的命令行接口
35+
36+
## 构建和安装
37+
38+
### 编译模块
39+
40+
`framework/fit/java` 目录下执行:
41+
42+
```bash
43+
mvn clean install
44+
```
45+
46+
编译完成后,会生成:
47+
- `fit-discrete-launcher-{version}.jar`: 启动器 JAR 文件
48+
- `build/bin/`: 启动脚本目录
49+
50+
### 构建产物
51+
52+
```
53+
build/
54+
├── fit-discrete-launcher-3.5.5-SNAPSHOT.jar
55+
└── bin/
56+
├── fit # Unix/Linux/macOS 启动脚本
57+
├── fit.js # Node.js 核心脚本
58+
└── fit.cmd # Windows 启动脚本
59+
```
60+
61+
## 启动脚本使用说明
62+
63+
### 前置要求
64+
65+
- **Node.js**: 12.0+ (推荐 16.0+)
66+
- **Java**: 17+
67+
68+
### Unix/Linux/macOS 使用方法
69+
70+
#### 启动应用
71+
72+
```bash
73+
./fit start [Java参数] [程序参数]
74+
```
75+
76+
**示例:**
77+
```bash
78+
# 基本启动
79+
./fit start
80+
81+
# 指定 JVM 内存参数
82+
./fit start -Xmx1g -Xms512m
83+
84+
# 传递应用参数
85+
./fit start -Xmx1g myapp config.yaml
86+
```
87+
88+
#### Debug 模式启动
89+
90+
```bash
91+
./fit debug [Java参数] [程序参数]
92+
```
93+
94+
Debug 模式会自动添加以下 JVM 参数:
95+
```
96+
-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
97+
```
98+
99+
启动后可以使用 IDE(如 IntelliJ IDEA)连接到端口 5005 进行远程调试。
100+
101+
#### 查看版本
102+
103+
```bash
104+
./fit version
105+
```
106+
107+
#### 查看帮助
108+
109+
```bash
110+
./fit help
111+
```
112+
113+
### Windows 使用方法
114+
115+
使用 `fit.cmd` 命令:
116+
117+
```cmd
118+
# 启动应用
119+
fit.cmd start
120+
121+
# Debug 模式启动
122+
fit.cmd debug
123+
124+
# 查看版本
125+
fit.cmd version
126+
127+
# 查看帮助
128+
fit.cmd help
129+
130+
# 传递参数
131+
fit.cmd start -Xmx1g -Xms512m myapp config.yaml
132+
```
133+
134+
### 参数传递机制
135+
136+
启动脚本会自动区分 Java 参数和程序参数:
137+
138+
- **Java 参数**: 以 `-` 开头的参数(如 `-Xmx512m``-Dproperty=value`
139+
- **程序参数**: 不以 `-` 开头的参数
140+
141+
**完整示例:**
142+
```bash
143+
./fit start -Xmx1g -Dplugin.path=/custom/path myapp config.yaml
144+
```
145+
146+
实际执行的 Java 命令:
147+
```bash
148+
java -Xmx1g -Dplugin.path=/custom/path \
149+
-Dsun.io.useCanonCaches=true \
150+
-Djdk.tls.client.enableSessionTicketExtension=false \
151+
-Dplugin.fit.dynamic.plugin.directory=/current/working/directory \
152+
-jar fit-discrete-launcher-3.5.5-SNAPSHOT.jar \
153+
myapp config.yaml
154+
```
155+
156+
### 环境变量和系统属性
157+
158+
启动脚本会自动设置以下 Java 系统属性:
159+
160+
| 系统属性 | 默认值 | 说明 |
161+
|---------|--------|------|
162+
| `sun.io.useCanonCaches` | `true` | 启用文件路径缓存,提升性能 |
163+
| `jdk.tls.client.enableSessionTicketExtension` | `false` | 禁用 TLS 会话票证扩展 |
164+
| `plugin.fit.dynamic.plugin.directory` | 当前工作目录 | 动态插件加载目录 |
165+
166+
## 技术实现
167+
168+
### 启动脚本实现(Node.js)
169+
170+
#### 为什么使用 Node.js?
171+
172+
相比传统的 Bash 脚本,Node.js 实现具有以下优势:
173+
174+
1. **跨平台兼容性**: 可以在 Windows、Linux、macOS 上无缝运行
175+
2. **无需特殊处理**: 避免了 Shell 脚本在不同系统上的兼容性问题(如 macOS 上的 `readlink -f`
176+
3. **更好的可维护性**: JavaScript 语法更容易理解和维护
177+
4. **统一的开发体验**: 与现代开发工具保持一致
178+
179+
#### 脚本工作原理
180+
181+
1. 解析命令行参数
182+
2. 区分 Java 参数和程序参数
183+
3. 在脚本所在目录的上级目录查找 `fit-discrete-launcher-*.jar` 文件
184+
4. 构造完整的 Java 命令
185+
5. 使用 `child_process.spawn` 启动 Java 进程
186+
6. 继承标准输入/输出/错误流
187+
7. 正确处理进程信号(SIGINT、SIGTERM)
188+
189+
### 类加载器实现
190+
191+
#### SharedClassLoader
192+
193+
加载共享类库,位于 `lib/shared/` 目录:
194+
- 基础工具类
195+
- 日志框架
196+
- 其他共享依赖
197+
198+
#### FrameworkClassLoader
199+
200+
加载 FIT 框架核心类,位于 `lib/framework/` 目录:
201+
- FIT IoC 容器
202+
- FIT 插件系统
203+
- FIT 运行时
204+
205+
## 故障排除
206+
207+
### 找不到 JAR 文件
208+
209+
**错误信息:**
210+
```
211+
No fit-discrete-launcher-[version].jar file found.
212+
```
213+
214+
**解决方法:**
215+
1. 确保已经编译了项目:`mvn clean install`
216+
2. 检查 `bin/..` 目录下是否存在 `fit-discrete-launcher-*.jar` 文件
217+
3. 确保脚本在正确的位置执行
218+
219+
### Node.js 未安装
220+
221+
**错误信息:**
222+
```
223+
bash: node: command not found
224+
```
225+
226+
```
227+
'node' 不是内部或外部命令...
228+
```
229+
230+
**解决方法:**
231+
[Node.js 官网](https://nodejs.org/) 下载并安装 Node.js。
232+
233+
### Java 未安装或版本不正确
234+
235+
**错误信息:**
236+
```
237+
Failed to start Java process: spawn java ENOENT
238+
```
239+
240+
**解决方法:**
241+
1. 安装 Java 17 或更高版本
242+
2. 确保 `java` 命令在系统 PATH 中
243+
244+
验证 Java 安装:
245+
```bash
246+
java -version
247+
```
248+
249+
### 类加载错误
250+
251+
**错误信息:**
252+
```
253+
ClassNotFoundException: ...
254+
```
255+
256+
**可能原因:**
257+
1. 缺少必要的依赖库
258+
2. 类加载器配置错误
259+
3. JAR 文件损坏
260+
261+
**解决方法:**
262+
1. 检查 `lib/` 目录下的依赖是否完整
263+
2. 重新编译和打包应用
264+
3. 查看详细的错误日志
265+
266+
## 与其他启动方式的对比
267+
268+
FIT 框架支持多种启动方式:
269+
270+
| 启动方式 | 适用场景 | 类加载方式 | 进程模型 |
271+
|---------|---------|-----------|---------|
272+
| **Discrete Launcher** | 生产环境、独立部署 | 自定义类加载器 | 独立进程 |
273+
| IDE 直接启动 | 开发调试 | IDE 类加载器 | IDE 进程 |
274+
| Spring Boot 集成 | Spring Boot 应用 | Spring Boot 类加载器 | Spring Boot 进程 |
275+
| Aggregated Launcher | 聚合部署 | 共享类加载器 | 多应用单进程 |
276+
277+
## 相关文档
278+
279+
- [FIT 快速入门指南](../../docs/framework/fit/java/quick-start-guide/)
280+
- [FIT 用户指导手册](../../docs/framework/fit/java/user-guide-book/)
281+
- [启动程序设计](./设计文档链接)
282+
- [类加载架构设计](./设计文档链接)
283+
284+
## 兼容性
285+
286+
- **Node.js**: 12.0.0+ (推荐 16.0.0+)
287+
- **操作系统**: Windows 7+, macOS 10.12+, Linux (any modern distribution)
288+
- **Java**: 17+
289+
290+
## 贡献
291+
292+
如果你发现任何问题或有改进建议,请提交 Issue 或 Pull Request。
293+
294+
## 许可证
295+
296+
与 FIT 框架保持一致。
Lines changed: 3 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,3 @@
1-
#!/bin/bash
2-
3-
# 获取脚本所在的路径
4-
CURRENT_DIR=$(pwd)
5-
CMD_PATH=$(dirname $(readlink -f $0))
6-
7-
# 定义版本号
8-
VERSION="3.5.5-SNAPSHOT"
9-
10-
function start {
11-
local DEBUG_ARGS=""
12-
if [ "$1" == "debug" ]; then
13-
DEBUG_ARGS=" -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
14-
fi
15-
16-
# 初始化变量
17-
JAVA_ARGS=""
18-
PROGRAM_ARGS=""
19-
20-
# 迭代所有的参数,跳过第一个参数("start"或"debug")
21-
shift
22-
for arg in "$@"; do
23-
# 检查参数是否以-开头
24-
if [[ $arg == -* ]]; then
25-
JAVA_ARGS="$JAVA_ARGS $arg"
26-
else
27-
PROGRAM_ARGS="$PROGRAM_ARGS $arg"
28-
fi
29-
done
30-
31-
cd $CMD_PATH/..
32-
# 查找符合 fit-discrete-launcher-[version].jar 格式的文件
33-
JAR_FILE=$(ls | grep "fit-discrete-launcher-.*.jar" | head -n 1)
34-
if [ -z "$JAR_FILE" ]; then
35-
echo "No fit-discrete-launcher-[version].jar file found."
36-
else
37-
# 构造并运行 Java 命令
38-
echo "Running command: java${DEBUG_ARGS}${JAVA_ARGS} -D\"sun.io.useCanonCaches=true\" -D\"plugin.fit.dynamic.plugin.directory=${CURRENT_DIR}\" -jar ${JAR_FILE}${PROGRAM_ARGS}"
39-
java${DEBUG_ARGS}${JAVA_ARGS} -D"sun.io.useCanonCaches=true" -D"jdk.tls.client.enableSessionTicketExtension=false" -D"plugin.fit.dynamic.plugin.directory=${CURRENT_DIR}" -jar ${JAR_FILE}${PROGRAM_ARGS}
40-
fi
41-
}
42-
43-
function version {
44-
echo "Version: $VERSION"
45-
}
46-
47-
function help {
48-
echo "Usage: fit <command> [arguments]"
49-
echo "Commands:"
50-
echo " start Start the application"
51-
echo " debug Start the application in debug mode"
52-
echo " version Display the version number"
53-
echo " help Display this help message"
54-
}
55-
56-
# 根据输入的参数执行相应的函数
57-
case "$1" in
58-
start)
59-
start "$@"
60-
;;
61-
debug)
62-
start "$@"
63-
;;
64-
version)
65-
version
66-
;;
67-
help)
68-
help
69-
;;
70-
*)
71-
echo "Unknown command: $1"
72-
echo "Run 'fit help' for usage."
73-
exit 1
74-
esac
1+
#!/usr/bin/env node
2+
// 这个文件会直接执行 fit.js
3+
require('./fit.js');

framework/fit/java/fit-launcher/src/main/resources/bin/fit.bat

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@echo off
2+
node "%~dp0fit.js" %*

0 commit comments

Comments
 (0)