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