docs(work): add PR7950 package startup flow summary
This commit is contained in:
@@ -0,0 +1,321 @@
|
|||||||
|
---
|
||||||
|
title: PR7950 Java 打包启动流程说明
|
||||||
|
icon: fa6-solid:box-archive
|
||||||
|
date: 2026-05-11
|
||||||
|
category:
|
||||||
|
- 工作
|
||||||
|
tag:
|
||||||
|
- PR7950
|
||||||
|
- Java
|
||||||
|
- 打包
|
||||||
|
- XJar
|
||||||
|
- 启动流程
|
||||||
|
---
|
||||||
|
|
||||||
|
# PR7950 Java 打包、压缩、XJar 加密与启动流程说明
|
||||||
|
|
||||||
|
整个流程从 `build.sh` 开始,先构建 Java 模块,再按清单提取业务 fat jar,随后用压缩工具拆分公共依赖,再使用 XJar 加密,最后把产物同步到 `binary/java` 运行目录。启动时不是直接执行 `java -jar`,而是通过 `xjar java ... -jar 服务.jar` 解密运行。
|
||||||
|
|
||||||
|
<!-- more -->
|
||||||
|
|
||||||
|
## 1. 总体流程
|
||||||
|
|
||||||
|
整个流程从 `build.sh` 开始,先构建 Java 模块,再按清单提取业务 fat jar,随后用压缩工具拆分公共依赖,再使用 XJar 加密,最后把产物同步到 `binary/java` 运行目录。启动时不是直接执行 `java -jar`,而是通过 `xjar java ... -jar 服务.jar` 解密运行。
|
||||||
|
|
||||||
|
### 流程步骤
|
||||||
|
|
||||||
|
1. **build.sh**: 准备 JDK/Maven,同步 encrypt XML
|
||||||
|
2. **Maven Build**: 构建 platform 与 platapp
|
||||||
|
3. **x64_raw**: 按 jar_list.txt 提取原始 fat jar
|
||||||
|
4. **compress**: 拆分 BOOT-INF/lib 依赖
|
||||||
|
5. **lib/common**: 输出公共 jar 与 requirements.txt
|
||||||
|
6. **XJar**: 加密压缩后的服务 jar
|
||||||
|
7. **binary**: 同步 jar 与公共依赖到运行目录
|
||||||
|
8. **startup**: xjar java 启动,动态加载公共依赖
|
||||||
|
|
||||||
|
> **一句话概括:**
|
||||||
|
> 打包阶段把业务 jar 变小并加密,启动阶段用 XJar 解密运行,再由 `sunri-spring-classload` 把拆出去的公共依赖加载回来。
|
||||||
|
|
||||||
|
## 2. 构建与提取 Jar
|
||||||
|
|
||||||
|
入口脚本位于:
|
||||||
|
`/home/liumangmang/IdeaProjects/PR7950/V1.00_2024/src_java/package/build.sh`
|
||||||
|
|
||||||
|
### 执行入口
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/liumangmang/IdeaProjects/PR7950/V1.00_2024/src_java/package
|
||||||
|
bash build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 环境准备
|
||||||
|
|
||||||
|
脚本根据机器架构选择内置 JDK,并使用项目自带 Maven。
|
||||||
|
|
||||||
|
| 项目 | 路径/规则 |
|
||||||
|
| :--- | :--- |
|
||||||
|
| x86_64 JDK | `src_java/package/jdk-x64` |
|
||||||
|
| ARM JDK | `src_java/package/jdk-arm` |
|
||||||
|
| Maven | `src_java/package/maven` |
|
||||||
|
| 原始 jar 目标目录 | `src_java/package/java/jar/x64_raw` |
|
||||||
|
|
||||||
|
### Maven 构建顺序
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd src_java/platform
|
||||||
|
mvn clean install -DskipTests -T 1C
|
||||||
|
|
||||||
|
cd src_java/platapp
|
||||||
|
mvn clean package -DskipTests -T 1C
|
||||||
|
```
|
||||||
|
|
||||||
|
### 按 jar_list.txt 提取业务 Jar
|
||||||
|
|
||||||
|
`build.sh` 读取 `src_java/package/jar_list.txt`,在 `platform` 和 `platapp` 的 `target` 目录中查找同名 jar,排除 `original-*`,复制到 `x64_raw`。
|
||||||
|
|
||||||
|
```text
|
||||||
|
src_java/package/jar_list.txt
|
||||||
|
src_java/platform/**/target/*.jar
|
||||||
|
src_java/platapp/**/target/*.jar
|
||||||
|
↓
|
||||||
|
src_java/package/java/jar/x64_raw/*.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 压缩与依赖拆分
|
||||||
|
|
||||||
|
压缩工具源码位于:
|
||||||
|
`/home/liumangmang/IdeaProjects/PR7950/V1.00_2024/src_java/tool/sunri-package-compress-xjar/`
|
||||||
|
|
||||||
|
构建产物是带依赖的可执行 jar:
|
||||||
|
`target/sunri-package-compress-xjar-1.0-jar-with-dependencies.jar`
|
||||||
|
|
||||||
|
### 配置文件
|
||||||
|
|
||||||
|
脚本从模板生成实际配置:
|
||||||
|
`src_java/package/java/tools/model_compress-xjar.config` -> `src_java/package/java/tools/compress-xjar.config`
|
||||||
|
|
||||||
|
| 配置项 | 作用 |
|
||||||
|
| :--- | :--- |
|
||||||
|
| `entryptXmlDir` | 读取每个服务的加密/保留依赖 XML,实际来自 `src_java/package/java/bin/encrypt/` |
|
||||||
|
| `rawJarDir` | 原始 fat jar 输入目录:`src_java/package/java/jar/x64_raw` |
|
||||||
|
| `compressJarDir` | 压缩后 jar 输出目录:`src_java/package/java/jar/x64_compress` |
|
||||||
|
| `libDir` | 被拆出去的公共依赖输出目录:`src_java/package/java/lib/common` |
|
||||||
|
| `xjarDir` | XJar 加密后 jar 输出目录:`src_java/package/java/jar/x64` |
|
||||||
|
| `enableCompress` | `1` 启用压缩,`0` 不压缩 |
|
||||||
|
|
||||||
|
### 依赖拆分规则
|
||||||
|
|
||||||
|
压缩逻辑在 `JarUtil.compress` 中实现,扫描 Spring Boot fat jar 的 `BOOT-INF/lib/*.jar`。符合以下条件的依赖会保留在业务 jar 内,其余依赖会被提取到 `lib/common`。
|
||||||
|
|
||||||
|
* `cygbusiness-*` 开头的 jar 保留。
|
||||||
|
* `sunri-*` 开头的 jar 保留。
|
||||||
|
* 当前服务 XML 的 `<include>` 中声明的 jar 保留。
|
||||||
|
* 其他 jar 从业务 jar 删除,并复制到 `lib/common`。
|
||||||
|
|
||||||
|
每个服务还会生成一个依赖清单:
|
||||||
|
`src_java/package/java/lib/common/服务名-requirements.txt`
|
||||||
|
|
||||||
|
该清单记录当前服务启动时需要从公共目录加载哪些被拆出去的 jar。
|
||||||
|
|
||||||
|
## 4. XJar 加密
|
||||||
|
|
||||||
|
压缩后,工具使用 XJar 对服务 jar 加密。相关代码位于:
|
||||||
|
`src_java/tool/sunri-package-compress-xjar/src/main/java/com/sunri/Main.java`
|
||||||
|
|
||||||
|
使用的依赖是:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.core-lib</groupId>
|
||||||
|
<artifactId>xjar</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 默认加密参数
|
||||||
|
|
||||||
|
| 项目 | 值 |
|
||||||
|
| :--- | :--- |
|
||||||
|
| 密码 | `xtptweb` |
|
||||||
|
| include | `/com/sunri/**`, `*.yaml`, `mapper/**.xml`, `*.yml` |
|
||||||
|
| exclude | 空 |
|
||||||
|
|
||||||
|
工具先输出 `服务名.xjar`,成功后再重命名为 `服务名.jar`。因此发布目录中看到的是 `.jar` 文件,但内容已经经过 XJar 处理。
|
||||||
|
|
||||||
|
```text
|
||||||
|
x64_compress/服务名.jar
|
||||||
|
↓ XJar encryption
|
||||||
|
x64/服务名.xjar
|
||||||
|
↓ rename
|
||||||
|
x64/服务名.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
> **注意:**
|
||||||
|
> `src_java/platform/01_componnet/08_sunri-package-xjar/` 是历史/图形化加密工具组件;当前 `build.sh` 实际调用的是 `src_java/tool/sunri-package-compress-xjar/`。
|
||||||
|
|
||||||
|
## 5. 同步到 binary 运行目录
|
||||||
|
|
||||||
|
加密后的服务 jar 从源码打包目录复制到运行目录:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src_java/package/java/jar/x64/*.jar
|
||||||
|
↓
|
||||||
|
binary/java/jar/x64/*.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
公共依赖和 `*-requirements.txt` 从源码打包目录复制到运行目录:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src_java/package/java/lib/common/
|
||||||
|
↓
|
||||||
|
binary/java/lib/common/
|
||||||
|
```
|
||||||
|
|
||||||
|
最终运行目录关键结构如下:
|
||||||
|
|
||||||
|
```text
|
||||||
|
binary/java/bin/
|
||||||
|
binary/java/bin/encrypt/
|
||||||
|
binary/java/jar/x64/
|
||||||
|
binary/java/jar/x64/xjar
|
||||||
|
binary/java/lib/common/
|
||||||
|
```
|
||||||
|
|
||||||
|
> **关键前提:**
|
||||||
|
> `binary/java/jar/x64/xjar` 是 Linux x86_64 可执行文件,启动加密 jar 时必须存在并具备执行权限。当前 `build.sh` 不负责编译这个可执行文件,只依赖运行目录已预置。
|
||||||
|
|
||||||
|
## 6. 启动流程
|
||||||
|
|
||||||
|
业务启动脚本位于:
|
||||||
|
`/home/liumangmang/IdeaProjects/PR7950/V1.00_2024/binary/java/bin/`
|
||||||
|
|
||||||
|
启动前需要设置 `PRJHOME` 指向项目运行根目录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export PRJHOME=/home/liumangmang/IdeaProjects/PR7950/V1.00_2024
|
||||||
|
```
|
||||||
|
|
||||||
|
### 启动、停止、重启示例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ${PRJHOME}/binary/java/bin/cygsystemweb.sh start
|
||||||
|
bash ${PRJHOME}/binary/java/bin/cygsystemweb.sh stop
|
||||||
|
bash ${PRJHOME}/binary/java/bin/cygsystemweb.sh restart
|
||||||
|
```
|
||||||
|
|
||||||
|
每个业务脚本都会设置服务名、jar 路径、公共依赖路径和 JVM 参数,然后调用统一控制脚本:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
JAVA_PROC_ROOT=${PRJHOME}/binary/java
|
||||||
|
JAVA_PROC_NAME="cygsystemweb"
|
||||||
|
JAVA_PROC_JAR_PATH=${JAVA_PROC_ROOT}/jar/x64/${JAVA_PROC_NAME}.jar
|
||||||
|
JAVA_PROC_LIB_PATH=${JAVA_PROC_ROOT}/lib/common
|
||||||
|
JVM_OPTS="-Xms512M -Xmx512M"
|
||||||
|
|
||||||
|
/bin/bash ${JAVA_PROC_ROOT}/bin/javacontrol.sh \
|
||||||
|
${JAVA_PROC_JAR_PATH} start ${JAVA_PROC_LIB_PATH} "${JVM_OPTS}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### javacontrol.sh 最终命令
|
||||||
|
|
||||||
|
真正启动时不是直接 `java -jar`,而是通过 `xjar` 包装 `java` 命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nohup ${PRJHOME}/binary/java/jar/x64/xjar java \
|
||||||
|
-Dplainload.dir.path=${PRJHOME}/binary/java/lib/common \
|
||||||
|
-Djava.io.tmpdir=/home/sunri/patrolTemp \
|
||||||
|
-Dplainload.include.file=cygsystemweb-requirements.txt \
|
||||||
|
-DenableSkipAuth=false \
|
||||||
|
-Djava.net.preferIPv4Stack=true \
|
||||||
|
-Dfile.encoding=utf-8 \
|
||||||
|
-Duser.timezone=Asia/Shanghai \
|
||||||
|
-Drds.dynamic.sql=true \
|
||||||
|
-Xms512M -Xmx512M \
|
||||||
|
-XX:+UseG1GC \
|
||||||
|
-XX:ParallelGCThreads=8 \
|
||||||
|
-XX:NativeMemoryTracking=summary \
|
||||||
|
-jar ${PRJHOME}/binary/java/jar/x64/cygsystemweb.jar \
|
||||||
|
> /dev/null 2>&1 &
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. 动态加载公共依赖
|
||||||
|
|
||||||
|
公共依赖动态加载组件位于:
|
||||||
|
`/home/liumangmang/IdeaProjects/PR7950/V1.00_2024/src_java/platform/01_componnet/06_sunri-spring-classload/`
|
||||||
|
|
||||||
|
该组件通过 `META-INF/spring.factories` 注册 Spring Boot 早期监听器:
|
||||||
|
|
||||||
|
```text
|
||||||
|
org.springframework.context.ApplicationListener=\
|
||||||
|
com.sunri.PlainTextClassLoader
|
||||||
|
```
|
||||||
|
|
||||||
|
`PlainTextClassLoader` 启动时读取两个 JVM 参数:
|
||||||
|
|
||||||
|
| 参数 | 作用 |
|
||||||
|
| :--- | :--- |
|
||||||
|
| `-Dplainload.dir.path` | 公共依赖目录,例如 `binary/java/lib/common` |
|
||||||
|
| `-Dplainload.include.file` | 当前服务的依赖清单,例如 `cygsystemweb-requirements.txt` |
|
||||||
|
|
||||||
|
加载过程是:读取 `binary/java/lib/common/服务名-requirements.txt`,再把清单中的 jar 通过反射调用 `URLClassLoader.addURL` 加入当前 classloader。
|
||||||
|
|
||||||
|
```text
|
||||||
|
binary/java/lib/common/
|
||||||
|
├── cygsystemweb-requirements.txt
|
||||||
|
├── jackson-databind-*.jar
|
||||||
|
├── mysql-connector-*.jar
|
||||||
|
└── ...
|
||||||
|
|
||||||
|
PlainTextClassLoader
|
||||||
|
↓ read requirements
|
||||||
|
↓ addURL(jar)
|
||||||
|
Spring Boot application continues startup
|
||||||
|
```
|
||||||
|
|
||||||
|
> **运行时 classpath 组成:**
|
||||||
|
> 加密服务 jar 内保留的依赖,加上 `lib/common` 中按 `requirements.txt` 动态加载的依赖。
|
||||||
|
|
||||||
|
## 8. 新增服务维护清单
|
||||||
|
|
||||||
|
如果后续新增一个 Java 服务,需要同时维护以下内容,保证打包和启动链路完整。
|
||||||
|
|
||||||
|
* 在 `src_java/package/jar_list.txt` 增加 `新服务.jar`。
|
||||||
|
* 确认 Maven 构建后能在 `platform` 或 `platapp` 的 `target` 下生成同名 jar。
|
||||||
|
* 在 `binary/java/bin/encrypt/` 增加 `新服务.xml`,并确保根节点 `service="新服务"`。
|
||||||
|
* 在 XML 中声明压缩后必须保留在业务 jar 内的依赖,尤其是 Spring Boot 核心依赖、启动早期依赖、业务 SPI 和不能拆出的内部包。
|
||||||
|
* 在 `binary/java/bin/` 增加 `新服务.sh`,设置 `JAVA_PROC_NAME`、`JVM_OPTS` 等参数。
|
||||||
|
* 执行 `build.sh` 后确认生成 `binary/java/jar/x64/新服务.jar`。
|
||||||
|
* 确认生成 `binary/java/lib/common/新服务-requirements.txt`。
|
||||||
|
* 启动前确认 `PRJHOME`、`xjar` 执行权限、公共依赖目录都正确。
|
||||||
|
|
||||||
|
## 9. 快速参考
|
||||||
|
|
||||||
|
### 打包命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/liumangmang/IdeaProjects/PR7950/V1.00_2024/src_java/package
|
||||||
|
bash build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 启动命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export PRJHOME=/home/liumangmang/IdeaProjects/PR7950/V1.00_2024
|
||||||
|
bash ${PRJHOME}/binary/java/bin/cygsystemweb.sh start
|
||||||
|
```
|
||||||
|
|
||||||
|
### 加密后 Jar
|
||||||
|
|
||||||
|
```text
|
||||||
|
binary/java/jar/x64/*.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
### 公共依赖
|
||||||
|
|
||||||
|
```text
|
||||||
|
binary/java/lib/common/
|
||||||
|
binary/java/lib/common/*-requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
本文档根据当前仓库脚本和源码整理,重点覆盖 `build.sh`、`sunri-package-compress-xjar`、`sunri-spring-classload`、XJar 运行入口与 `binary/java/bin` 启动脚本。
|
||||||
Reference in New Issue
Block a user