基于APT(Annotation Processing Tool)实现业务实体功能增强.提供包装类,便于自定义代码增强相关逻辑开发
后端程序返回的数据中, 包含跳转Url / 资源Url等内容.
- 我方网络环境与客户端网络环境存在差异, 我方可正确访问的资源,客户端不一定可以正确访问.
- Request 中持有用户的访问域名
- 无侵入式的将该域名扩散到所有Response Url中
- 可用性: 该修改过程必须对前端不可见
- 可维护性: 该修改过程不应占用过多系统资源
- 可扩展性: 该修改过程不易过度繁琐
经过调研, 最终可选方案为: Aop / JDKProxy / CglibProxy / Apt
方案 | 优点 | 缺点 |
---|---|---|
Aop 增强 | 代码结构紧凑,修改过程由Spring维护,易读易扩展 | 替换逻辑复杂:Response结构复杂,需要深度遍历所有遍历,逻辑开销大 |
JDK 代理 | 只需增强需要修改的对象,替换逻辑简单; | 无形中多维护一套实体,需要修改所有初始化代码;需要定义额外接口; |
Cglib 代理 | 不定义额外接口,只需修改特定对象,替换逻辑简单 | 存在额外性能开销, 需要修改所有初始化代码 |
Apt 增强 | 编译时期增强, 性能优越 | 需要标注要修改的属性, 不可动态修改;存在学习成本 |
前置条件:
- 假设目标实体类中包含且仅包含唯一需要修改的字段
- 请求过程中没有额外业务逻辑 (创建对象后立即返回)
- 不考虑网络IO/文件IO等开销
- 每种方案指定 1000,000 次
实际业务场景中, 实体类相关操作逻辑只占了整个请求过程的一部分, 对比结果可能没有那么明显.
对比结果:
各增强方案性能对比指标 | 无修改 | APT | Aop | JdkProxy | CglibProxy |
---|---|---|---|---|---|
时间(单位:ms) | 149 | 148 | 3982 | 1359 | 1292 |
从上图我们可以发现, APT在性能上具有明显的优势
域名相关资源通过 ThreadLocal 封装在静态资源中, 满足编译期间获取; 遍历所有实体类, 为对应属性添加注解的开发成本在可容忍的范围内;
最终选择 APT 作为我方域名替换实现方案.
- base_structure: 工具包, 负责具体域名替换逻辑 & 业务逻辑, 作为lib集成到业务程序中
- class_reinforce: 各方案实现代码
- aop_scaffold: Aop增强方案相关代码(目前仅支持对最外层class增强)
- apt_scaffold: APT增强方案相关代码(不支持对内部类进行增强, 感兴趣可以自己实现)
- proxy_cglib_scaffold: cglib 代理方案相关代码
- proxy_java_scaffold: jdk 代理方案相关代码
动态的Java - 无废话JavaCompilerAPI中文指南 - Meta-Interpretation (pfmiles.github.io))
square/javapoet:用于生成.java源文件的Java API。 (github.com)
projectlombok/lombok: Very spicy additions to the Java programming language. (github.com)
mplushnikov/lombok-intellij-plugin: Lombok Plugin for IntelliJ IDEA (github.com)
jflex-de/jflex:Java的™快速扫描仪生成器,具有完整的Unicode支持 (github.com)
IDEA插件在 plugin 分支