提交UI自动化插件
This commit is contained in:
@@ -1,509 +0,0 @@
|
||||
# api-trim-maven-plugin 架构设计
|
||||
|
||||
## 1. 问题定义
|
||||
|
||||
API 模块旨在为网关桥应用提供 RPC 接口调用能力,理想的 JAR 依赖范围应限于:
|
||||
|
||||
- RPC 接口定义
|
||||
- 入参/出参 DTO 模型
|
||||
- 序列化注解与类型
|
||||
|
||||
实际产生的冗余:
|
||||
|
||||
| 冗余来源 | 示例 |
|
||||
|---------|------|
|
||||
| 实现类 | `*ServiceImpl.java`、`*ManagerImpl.java` |
|
||||
| 内部工具体系 | `*Utils.java`、`*Helper.java`、`*Converter.java` |
|
||||
| Spring 配置/自动装配 | `*Config.java`、`*AutoConfiguration.java` |
|
||||
| 数据层依赖 | MyBatis Mapper、JDBC Driver、DataSource |
|
||||
| 传递依赖 | 由实现类引入的 spring-boot-starter-*、数据库连接池、缓存等 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 整体架构
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ api-trim-maven-plugin │
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ Goal: api-trim:trim (默认绑定 package 阶段) │
|
||||
│ api-trim:analyze(仅分析,不修改产物) │
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ ┌──────────────┐ │
|
||||
│ ① analyze │ 依赖分析器 │ ASM 字节码扫描 │
|
||||
│ │ Analyzer │ Maven 依赖树解析 │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ ② trim │ 精简执行器 │ 类/资源白名单策略 │
|
||||
│ │ Trimmer │ 依赖重写 或 shade │
|
||||
│ └──────┬───────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ ③ verify │ 安全校验器 │ 接口契约 diff │
|
||||
│ │ Verifier │ 字节码引用完整性 │
|
||||
│ └──────────────┘ │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心组件详细设计
|
||||
|
||||
### 3.1 依赖分析器(Analyzer)
|
||||
|
||||
分析器负责区分「RPC 必需的 API 表面」与「冗余实现及传递依赖」。
|
||||
|
||||
#### 3.1.1 三阶段分析
|
||||
|
||||
```
|
||||
阶段1:入口类识别
|
||||
├─ 扫描目标模块 compiled classes
|
||||
├─ 按注解识别 RPC 服务接口
|
||||
│ ├─ @DubboService / @Service(interfaceClass=...)
|
||||
│ ├─ @FeignClient
|
||||
│ ├─ @RestController / @RequestMapping(若 API 模块含 HTTP 接口)
|
||||
│ ├─ gRPC Service 基类子类
|
||||
│ └─ 用户通过 <apiInterfaces> 显式声明
|
||||
└─ 收集所有入口接口 → className[]
|
||||
|
||||
阶段2:可达性分析(类级别,ASM)
|
||||
├─ 以入口接口为根,BFS 遍历引用图
|
||||
│ ├─ 接口继承链(super interfaces)
|
||||
│ ├─ 方法签名中的类型(参数类型 + 返回类型 + 异常类型)
|
||||
│ │ └─ 递归解析泛型参数
|
||||
│ ├─ 注解类型引用(类注解 + 方法注解 + 字段注解)
|
||||
│ │ └─ 保留序列化相关注解:Jackson、Protobuf、Hessian、Fastjson 等
|
||||
│ └─ 父类中的字段类型
|
||||
└─ 输出:必需类集合 Set<ClassName>
|
||||
|
||||
阶段3:依赖坐标分析(Maven,可选)
|
||||
├─ 解析 dependency:tree
|
||||
├─ 对每个传递依赖:
|
||||
│ ├─ 若所含类均在「必需类集合」外 → 标记为可移除
|
||||
│ └─ 若所含类部分必需 → 保留(后续通过类级过滤处理)
|
||||
└─ 输出:可移除的 Maven 坐标列表
|
||||
```
|
||||
|
||||
#### 3.1.2 引用图遍历规则
|
||||
|
||||
```
|
||||
BFS 起点:所有入口接口
|
||||
遍历策略:
|
||||
┌─ 遇到类/接口 → 加入必需集 → 展开
|
||||
│ ├─ 父类 / 父接口 → 加入队列
|
||||
│ ├─ 泛型参数中引用的类 → 加入队列
|
||||
│ ├─ 方法参数/返回类型 → 加入队列
|
||||
│ ├─ 注解中引用的类 → 加入队列
|
||||
│ └─ 字段类型 → 加入队列(仅对 DTO 类)
|
||||
│
|
||||
├─ 遇到标准库类(java.* / javax.*) → 终止(不展开)
|
||||
├─ 遇到第三方库类 → 加入必需集但标记为 external(不影响 JAR 精简,仅用于依赖分析)
|
||||
└─ 遇到非目标模块类 → 记录为「外部依赖」,用于验证阶段
|
||||
```
|
||||
|
||||
#### 3.1.3 注解保留策略
|
||||
|
||||
```
|
||||
强制保留的注解分类:
|
||||
├─ 序列化注解
|
||||
│ ├─ Jackson: @JsonProperty, @JsonIgnore, @JsonFormat, @JsonTypeInfo...
|
||||
│ ├─ Protobuf: @Protobuf, @ProtoField...
|
||||
│ ├─ Hessian: java.io.Serializable(接口继承)
|
||||
│ └─ Fastjson: @JSONField
|
||||
│
|
||||
├─ 校验注解(RPC 调用方可能使用)
|
||||
│ └─ JSR-303: @NotNull, @Valid, @Size, @Pattern...
|
||||
│
|
||||
├─ API 文档注解
|
||||
│ └─ Swagger: @ApiModel, @ApiModelProperty(可选,根据配置)
|
||||
│
|
||||
└─ 业务注解(用户自定义)
|
||||
└─ 通过 <retainedAnnotations> 配置
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 精简执行器(Trimmer)
|
||||
|
||||
#### 3.2.1 策略对比与选择
|
||||
|
||||
| 策略 | 方案 | 优点 | 缺点 |
|
||||
|------|------|------|------|
|
||||
| **A: 类级过滤** | 重新打包 JAR,仅保留分析器输出的必需类 | 极致精简,JAR 最小 | 需要处理 MANIFEST、资源文件 |
|
||||
| **B: POM 重写** | 修改依赖声明,exclude 非必需传递依赖 | Maven 原生支持 | 粒度粗,一个 JAR 内可能只有几个类需要 |
|
||||
| **C: Shade + 过滤** | maven-shade-plugin + filters + minimizeJar | 成熟稳定 | 配置复杂,对 RPC 语义不感知 |
|
||||
|
||||
**推荐:策略 A(类级过滤)**,原因:
|
||||
- RPC API 模块依赖中,一个三方 JAR 可能包含 200 个类但仅 3 个 DTO 需要——B 粒度太粗
|
||||
- 策略 C 的 `minimizeJar` 对反射/序列化场景不够友好,可能有遗漏
|
||||
- 策略 A 基于可达性分析,天然感知 RPC 语义
|
||||
|
||||
#### 3.2.2 类级过滤执行流程
|
||||
|
||||
```
|
||||
输入:原始 JAR ← maven-jar-plugin 产物
|
||||
必需类集合 Set<ClassName> ← Analyzer
|
||||
<includes> 追加类 ← 用户配置
|
||||
<excludes> 排除类 ← 用户配置
|
||||
|
||||
流程:
|
||||
1. 创建临时目录 temp/
|
||||
2. 遍历原始 JAR 中所有条目:
|
||||
├─ *.class → 判断类全限定名是否在「必需集合 + includes」
|
||||
│ ├─ YES → 解压到 temp/
|
||||
│ └─ NO → 跳过
|
||||
│
|
||||
├─ META-INF/MANIFEST.MF → 保留
|
||||
├─ META-INF/spring.factories → 跳过(不含自动装配)
|
||||
├─ *.xml / *.properties(Spring 配置)→ 跳过
|
||||
├─ *.proto / *.avsc → 按需保留(若入口是 gRPC/Protobuf)
|
||||
└─ 其他资源 → 跳过
|
||||
|
||||
3. 重新打包 temp/ → ${project.build.finalName}-api.jar
|
||||
4. 可选:若启用 deps 重写,重写 POM 中依赖 scope
|
||||
```
|
||||
|
||||
#### 3.2.3 依赖 scope 重写
|
||||
|
||||
对于传递给下游的 POM,将非必需依赖标记为 `provided`:
|
||||
|
||||
```xml
|
||||
<!-- 原始 POM -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 精简后 POM -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<scope>provided</scope> <!-- 调用方自行提供 -->
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
#### 3.2.4 配置模型
|
||||
|
||||
```xml
|
||||
<plugin>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>api-trim-maven-plugin</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
|
||||
<!-- ===== 入口指定 ===== -->
|
||||
<!-- 自动扫描 RPC 注解类 + 手动指定 -->
|
||||
<apiInterfaces>
|
||||
<apiInterface>com.example.api.UserService</apiInterface>
|
||||
<apiInterface>com.example.api.OrderService</apiInterface>
|
||||
</apiInterfaces>
|
||||
|
||||
<!-- RPC 框架标识,影响注解扫描策略 -->
|
||||
<rpcFramework>DUBBO</rpcFramework> <!-- DUBBO | FEIGN | GRPC | SPRING_CLOUD | GENERIC -->
|
||||
|
||||
<!-- ===== 类过滤规则 ===== -->
|
||||
<retainedAnnotations>
|
||||
<annotation>com.example.MyBusinessAnnotation</annotation>
|
||||
</retainedAnnotations>
|
||||
|
||||
<retainedPackages>
|
||||
<package>com.example.common.dto.**</package>
|
||||
<package>com.example.common.enums.**</package>
|
||||
</retainedPackages>
|
||||
|
||||
<excludedPackages>
|
||||
<package>com.example.**.impl.**</package>
|
||||
<package>com.example.**.config.**</package>
|
||||
</excludedPackages>
|
||||
|
||||
<!-- ===== 依赖处理 ===== -->
|
||||
<dependencyStrategy>REWRITE_SCOPE</dependencyStrategy>
|
||||
<!-- PROVIDED_ONLY: 标记为 provided
|
||||
OPTIONAL_ONLY: 标记为 optional
|
||||
REMOVE: 从 POM 中完全移除 -->
|
||||
|
||||
<excludedDependencies> <!-- 指定 POM 中排除的传递依赖 -->
|
||||
<dependency>mysql:mysql-connector-java</dependency>
|
||||
<dependency>org.mybatis:*</dependency>
|
||||
</excludedDependencies>
|
||||
|
||||
<!-- ===== 安全 ===== -->
|
||||
<failOnBrokenReference>true</failOnBrokenReference>
|
||||
<outputReport>true</outputReport>
|
||||
</configuration>
|
||||
</plugin>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 Maven 生命周期集成
|
||||
|
||||
#### 3.3.1 Goal 绑定
|
||||
|
||||
```
|
||||
Goal: trim(默认)
|
||||
├─ 绑定阶段: package
|
||||
├─ 执行顺序: compile → jar → trim → [install/deploy]
|
||||
├─ requiresDependencyResolution: compile+runtime
|
||||
└─ 输出产物: ${project.build.finalName}-api.jar(替换默认 JAR)
|
||||
|
||||
Goal: analyze(诊断用)
|
||||
├─ 绑定阶段: verify(或手动执行 api-trim:analyze)
|
||||
├─ 输出: target/api-trim/report.txt
|
||||
└─ 可选: target/api-trim/dependency-graph.dot
|
||||
```
|
||||
|
||||
#### 3.3.2 执行时序
|
||||
|
||||
```
|
||||
mvn clean package
|
||||
|
||||
phase: compile → javac 编译
|
||||
phase: process-classes
|
||||
phase: prepare-package
|
||||
┌─────────────────┐
|
||||
phase: package ──────▶│ api-trim:trim │
|
||||
│ │
|
||||
│ 1. 解析入口接口 │
|
||||
│ 2. 字节码可达性 │
|
||||
│ 3. 构建白名单 │
|
||||
│ 4. JAR 重打包 │
|
||||
│ 5. POM rewrite │
|
||||
│ 6. 安全校验 │
|
||||
└────────┬────────┘
|
||||
│
|
||||
phase: verify ←──────────────┘ (report)
|
||||
phase: install → 安装精简后的 JAR 到本地仓库
|
||||
phase: deploy → 发布精简后的 JAR 到远程仓库
|
||||
```
|
||||
|
||||
#### 3.3.3 多模块项目集成
|
||||
|
||||
```
|
||||
parent
|
||||
├── api-module ← 在此模块配置 api-trim:trim
|
||||
│ └── pom.xml ← <plugin>api-trim-maven-plugin</plugin>
|
||||
├── service-module ← 实现模块,正常打包
|
||||
├── gateway-bridge ← 网关桥,依赖 api-module(会拿到精简版 JAR)
|
||||
└── pom.xml
|
||||
```
|
||||
|
||||
API 模块只需在 `pom.xml` 中声明该插件即可,其下游模块(gateway-bridge)通过普通 Maven 依赖机制拿到精简后的 JAR:
|
||||
|
||||
```xml
|
||||
<!-- gateway-bridge/pom.xml -->
|
||||
<dependency>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>api-module</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- 无需任何额外配置,直接引用即可 -->
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.4 安全保障与验证机制
|
||||
|
||||
#### 3.4.1 编译时校验
|
||||
|
||||
```
|
||||
校验项1:字节码引用完整性
|
||||
├─ 读取精简后的 classes 集合
|
||||
├─ 检查每个类的方法描述符中的所有类型引用
|
||||
├─ 若引用到未包含在 JAR 中的非标准库类 → ERROR
|
||||
└─ 区分:缺少的类在调用方 classpath 中 → WARN(需用户确认)
|
||||
|
||||
校验项2:序列化完整性
|
||||
├─ 对每个 DTO 类:
|
||||
│ ├─ 遍历所有字段 getter/setter
|
||||
│ ├─ 检查序列化注解是否被意外移除
|
||||
│ └─ 检查枚举值是否完整
|
||||
└─ 生成 SerializationTest.java 模板
|
||||
```
|
||||
|
||||
#### 3.4.2 运行时验证(可选,需用户配置测试类)
|
||||
|
||||
```
|
||||
验证方式:API 接口契约对比
|
||||
├─ 原始 JAR → 反射扫描所有 RPC 接口的方法签名 → Set<MethodSignature>
|
||||
├─ 精简 JAR → 同上
|
||||
├─ 对比两者:
|
||||
│ ├─ 方法数量一致
|
||||
│ ├─ 方法签名完全匹配(名称 + 参数 + 返回类型 + 异常)
|
||||
│ └─ 泛型签名一致
|
||||
└─ 不一致 → BUILD FAILURE
|
||||
|
||||
验证方式:序列化往返测试(自动生成测试代码)
|
||||
├─ 为每个 DTO 生成:
|
||||
│ public void test_${ClassName}_serialization() {
|
||||
│ ${ClassName} obj = new ${ClassName}();
|
||||
│ // ... populate random data
|
||||
│ byte[] data = serialize(obj);
|
||||
│ ${ClassName} result = deserialize(data);
|
||||
│ assertThat(result).isEqualTo(obj);
|
||||
│ }
|
||||
└─ 建议用户将此测试加入 CI 流程
|
||||
```
|
||||
|
||||
#### 3.4.3 报告输出
|
||||
|
||||
```
|
||||
target/api-trim/
|
||||
├── report.txt # 精简摘要
|
||||
│ ├── 原始 JAR 大小: 45.2 MB
|
||||
│ ├── 精简后 JAR 大小: 3.8 MB (↓ 91.6%)
|
||||
│ ├── 原始 class 数量: 8,342
|
||||
│ ├── 保留 class 数量: 312
|
||||
│ ├── 移除的传递依赖: 23 个
|
||||
│ └── 耗时: 1.2s
|
||||
│
|
||||
├── retained-classes.txt # 保留的类清单
|
||||
├── removed-classes.txt # 移除的类清单
|
||||
└── dependency-graph.dot # 依赖图(Graphviz)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 关键实现细节
|
||||
|
||||
### 4.1 可达性分析(核心算法)
|
||||
|
||||
```java
|
||||
public class ReachabilityAnalyzer {
|
||||
private final Set<String> retained = new HashSet<>();
|
||||
private final Queue<String> queue = new LinkedList<>();
|
||||
|
||||
public Set<String> analyze(Set<String> entryPoints, Path classesDir) {
|
||||
// Step 1: 注册入口
|
||||
queue.addAll(entryPoints);
|
||||
retained.addAll(entryPoints);
|
||||
|
||||
// Step 2: BFS
|
||||
while (!queue.isEmpty()) {
|
||||
String className = queue.poll();
|
||||
byte[] bytecode = readClass(classesDir, className);
|
||||
if (bytecode == null) continue; // 外部类,跳过
|
||||
|
||||
// 解析类引用
|
||||
for (String ref : parseReferences(bytecode)) {
|
||||
if (isStandardLibrary(ref)) continue;
|
||||
if (retained.add(ref)) {
|
||||
queue.add(ref); // 新发现,入队
|
||||
}
|
||||
}
|
||||
}
|
||||
return retained;
|
||||
}
|
||||
|
||||
private List<String> parseReferences(byte[] bytecode) {
|
||||
// 使用 ASM ClassReader
|
||||
// 提取:super class, interfaces, field types,
|
||||
// method param/return types, annotation types,
|
||||
// generic signatures
|
||||
|
||||
// CRITICAL: 递归解析泛型签名中的类型
|
||||
// 如 List<Map<String, OrderDetailDTO>> → OrderDetailDTO 必须保留
|
||||
List<String> refs = new ArrayList<>();
|
||||
// ... ASM visitor logic
|
||||
return refs;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 ASM Visitor 设计
|
||||
|
||||
```
|
||||
ApiSurfaceClassVisitor extends ClassVisitor
|
||||
├─ visit(version, access, name, signature, superName, interfaces)
|
||||
│ └─ 记录 superName + interfaces + signature(泛型)
|
||||
├─ visitAnnotation(desc, visible)
|
||||
│ └─ 记录注解类型(即使不在保留白名单,也记录引用)
|
||||
├─ visitField(access, name, desc, signature, value)
|
||||
│ └─ 记录: desc 中类型 + signature 中泛型 + 字段注解类型
|
||||
│ └─ 注意: desc="Lcom/example/UserDTO;" → 提取 UserDTO
|
||||
├─ visitMethod(access, name, desc, signature, exceptions)
|
||||
│ └─ 记录: 参数类型 + 返回类型 + 异常类型 + signature
|
||||
│ └─ desc="(ILcom/example/ReqDTO;)Lcom/example/RespDTO;"
|
||||
│ → 提取 ReqDTO, RespDTO
|
||||
└─ visitEnd()
|
||||
```
|
||||
|
||||
### 4.3 类名规范化
|
||||
|
||||
```
|
||||
字节码内部名 → 全限定类名转换:
|
||||
"com/example/UserService" → "com.example.UserService"
|
||||
"[Lcom/example/DTO;" → "com.example.DTO[]"(保留数组标记)
|
||||
"Lcom/example/Inner$Nested;" → "com.example.Inner$Nested"
|
||||
|
||||
跳过规则:
|
||||
java/* javax/* sun/* jdk/* → skip(JDK 标准库)
|
||||
[ZBSCIJFD → skip(8大基本类型 + void)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 典型使用场景
|
||||
|
||||
### 场景1:Dubbo API 模块
|
||||
|
||||
```xml
|
||||
<!-- API 模块 POM -->
|
||||
<plugin>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>api-trim-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<rpcFramework>DUBBO</rpcFramework>
|
||||
<!-- 自动扫描 @Service(interfaceClass=...) 找到所有 RPC 接口 -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
```
|
||||
|
||||
效果:
|
||||
- 移除所有 `*ServiceImpl`、`*ManagerImpl` 实现类
|
||||
- 移除 MyBatis、Spring Boot AutoConfigure、JDBC Driver
|
||||
- 保留 RPC 接口、DTO、枚举、自定义异常
|
||||
- JAR 从 45MB → ~3MB
|
||||
|
||||
### 场景2:Feign API 模块
|
||||
|
||||
```xml
|
||||
<plugin>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>api-trim-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<rpcFramework>FEIGN</rpcFramework>
|
||||
<!-- 自动扫描 @FeignClient 注解 -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 优先级与技术可行性
|
||||
|
||||
| 模块 | 可行性 | 复杂度 | 备注 |
|
||||
|------|--------|--------|------|
|
||||
| 入口扫描(注解识别) | ✅ 成熟 | 低 | ASM 读注解 |
|
||||
| 类级可达性分析 | ✅ 成熟 | 中 | BFS + ASM,已有类似工具(如 ProGuard) |
|
||||
| JAR 重打包 | ✅ 成熟 | 低 | Java NIO + JarOutputStream |
|
||||
| POM 依赖重写 | ✅ 成熟 | 低 | maven-model 库直接修改 |
|
||||
| 字节码引用完整性校验 | ✅ 可行 | 中 | ASM 二次扫描精简后 JAR |
|
||||
| 序列化验证 | ✅ 可行 | 中 | 需框架特定处理(Jackson/Protobuf/Hessian) |
|
||||
| 泛型签名解析 | ⚠️ 有坑 | 中-高 | signature 字段可能包含复杂泛型,需递归解析 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 与其他方案对比
|
||||
|
||||
| 方案 | JAR 大小 | 配置复杂度 | RPC 安全性 | 适用场景 |
|
||||
|------|----------|------------|------------|----------|
|
||||
| **api-trim-plugin** | ★★★★★ (3MB) | 中 | 高(ASM 可达性确保) | RPC API 模块专用 |
|
||||
| maven-shade minimizeJar | ★★★★ (5MB) | 高 | 中(反射不感知) | 通用 JAR 精简 |
|
||||
| maven-dependency exclude | ★★ (20MB+) | 低 | 高 | 粗粒度排除 |
|
||||
| 手工拆分模块 | ★★★★ | 很高 | 高 | 架构重构 |
|
||||
| ProGuard/R8 | ★★★★★ | 高 | 中(可能破坏序列化) | Android/通用混淆 |
|
||||
@@ -41,13 +41,6 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- ASM 字节码分析(API Trim 依赖) -->
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
<version>9.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MyBatis Generator Core -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.generator</groupId>
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
package com.example.workutils.biz.apitrimmer;
|
||||
|
||||
import com.example.workutils.biz.apitrimmer.service.ApiTrimmerService;
|
||||
import com.example.workutils.system.config.WorkUtilsProperties;
|
||||
import com.example.workutils.system.plugin.Plugin;
|
||||
import com.example.workutils.system.plugin.PluginDescriptor;
|
||||
import com.example.workutils.system.plugin.VisualPluginFactory;
|
||||
import com.example.workutils.system.support.JfxBootstrap;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.layout.Pane;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* API Trim 插件:精简 API JAR 包,移除冗余实现类与传递依赖。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ApiTrimmerPlugin implements Plugin {
|
||||
|
||||
private static final PluginDescriptor DESCRIPTOR = PluginDescriptor.builder()
|
||||
.id("api-trim")
|
||||
.name("API Trim")
|
||||
.version("1.0.0")
|
||||
.description("精简API模块JAR包,移除冗余实现类与传递依赖")
|
||||
.order(65)
|
||||
.icon("✂️")
|
||||
.build();
|
||||
|
||||
private static final String[] MENU_OPTIONS = {
|
||||
"1. UI可视化操作(选择JAR → 分析 → 精简)",
|
||||
"0. 返回上级菜单"
|
||||
};
|
||||
|
||||
private final ApiTrimmerService service;
|
||||
private final WorkUtilsProperties properties;
|
||||
|
||||
@Override public PluginDescriptor getDescriptor() { return DESCRIPTOR; }
|
||||
@Override public String[] getMenuOptions() { return MENU_OPTIONS; }
|
||||
|
||||
@Override
|
||||
public VisualPluginFactory getVisualFactory() {
|
||||
return new VisualPluginFactory() {
|
||||
private ApiTrimmerWindow window;
|
||||
private Parent embeddedRoot;
|
||||
private CountDownLatch latch;
|
||||
|
||||
@Override
|
||||
public Parent getEmbeddedPane() {
|
||||
if (embeddedRoot != null) return embeddedRoot;
|
||||
latch = new CountDownLatch(1);
|
||||
window = new ApiTrimmerWindow(service, properties, latch);
|
||||
embeddedRoot = window.getContentPane();
|
||||
window.getStage().getScene().setRoot(new Pane());
|
||||
return embeddedRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(Runnable onClosed) {
|
||||
if (window == null) {
|
||||
latch = new CountDownLatch(1);
|
||||
window = new ApiTrimmerWindow(service, properties, latch);
|
||||
}
|
||||
if (embeddedRoot != null && window.getStage().getScene().getRoot() != embeddedRoot) {
|
||||
window.getStage().getScene().setRoot(embeddedRoot);
|
||||
}
|
||||
window.show();
|
||||
new Thread(() -> {
|
||||
try { latch.await(); } catch (InterruptedException ignored) {}
|
||||
onClosed.run();
|
||||
}, "apitrim-close").start();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleChoice(int choice, Scanner scanner) throws Exception {
|
||||
if (choice == 1) {
|
||||
System.out.println("正在打开 API Trim 窗口...");
|
||||
JfxBootstrap.await();
|
||||
if (JfxBootstrap.isFailed()) {
|
||||
System.err.println("JavaFX 初始化失败");
|
||||
return;
|
||||
}
|
||||
CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
javafx.application.Platform.runLater(() ->
|
||||
new ApiTrimmerWindow(service, properties, closeLatch).show());
|
||||
closeLatch.await();
|
||||
System.out.println("API Trim 窗口已关闭");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
# API Trim 自动勾选目录名配置(每行一个关键词,忽略大小写,匹配即勾选)
|
||||
# 修改后保存,点击「刷新目录」即可生效
|
||||
lombok
|
||||
ttf
|
||||
class50
|
||||
Reference in New Issue
Block a user