S-MVP构建全流程揭秘:APT生成→AspectJ编织→Javassist注入→dex打包如何环环相扣
【免费下载链接】S-MVP优化版MVP,使用注解泛型简化代码编写使用模块化协议方便维护APT过程使用注解解析器利用JavaPoet完成重复模块的编写利用ASpectGradlePlugin 完成横向AOP编程Javassist动态字节码注入Tinker实现热修复Retrofit实现优雅网络操作RxJava轻松玩转数据处理项目地址https://gitcode.com/gh_mirrors/smv/S-MVP点击查看免费下载 S-MVP 是一个优化版 Android MVP 框架用注解泛型简化代码编写。它的最大亮点藏在编译期一次 Gradle 构建会串联起APT 注解生成代码 → AspectJ 织入切面 → Javassist 字节码注入 → dex 打包四个环节让你少写大量样板代码。本文将带你快速看懂这条构建流水线如何环环相扣。一、先看全景四大阶段各管一段在 README.md 中作者把处理流程总结为一句话在 build 过程我们可以通过 APT 生成 java 文件再通过 AspectJ 解析、编织成 class最后通过 Javassist 修改 class 和 jar 文件最终打包成 dex 到 apk。用一张表理清分工阶段技术处理对象产出代码位置1️⃣ APT 生成AnnotationProcessor JavaPoet注解元数据源码层新增.java文件libcomplier/2️⃣ AspectJ 编织aspectjtoolsajc已编译的 class织入切面逻辑的 classmyplugin/ 的AspectjPlugin3️⃣ Javassist 注入Gradle Transform javassistclass 文件注入 OkBus 注册/注销/分发代码的 classmyplugin/ 的JavassistTransform4️⃣ dex 打包AGPaapt/d8全部 classdex → APKAGP 默认流程下面按构建顺序逐个拆解。二、阶段一APT 注解处理器在编译期写代码2.1 入口一个 Processor 分发三个子处理器AnnotationProcessor.java 通过AutoService(Processor.class)自动注册它监听了InstanceFactory、$BindView、OnResume等注解然后在process()中依次调用InstanceProcessor—— 生成 Presenter 实例工厂BindViewProcessor—— 生成视图绑定类LifeProcessor—— 处理生命周期注解 生成的 Java 文件会落在app module/build/generated/source/apt目录下随后被正常编译。2.2 生成视图绑定类$$ViewBinder这是最直观的收益。你在字段上写一个注解构建期 BindViewProcessor.java 就会用 JavaPoet 生成类似MainActivity$$ViewBinder的类内部就是一连串findViewById的等价代码。运行时由 InjectView.java 通过反射Class.forName(className $$ViewBinder)找到并执行绑定于是 BaseAppCompatActivity 只需一行InjectView.bind(this)就完成了所有控件注入——注解定义见 $.java。2.3 生成 Presenter 实例工厂InstanceProcessor.java 则扫描所有标注InstanceFactory的类即各个 Presenter生成一个带switch的静态工厂方法配合 InstanceFactory.java 注解让 Presenter 的创建隐形——Activity 里不需要手写new XxxPresenter()。 两个细节值得注意生成的代码里尽量不要再加注解否则会触发下一轮注解处理形成递归源码注释中有说明InstanceFactory生成的create()方法本身还带了MemoryCache注解——也就是说 APT 的产物会被下一个阶段 AspectJ 继续加工这正是环环相扣的起点。三、阶段二AspectJ 在 class 文件上编织切面3.1 插件怎么介入构建AspectjPlugin.groovy 挂在javaCompile.doLast钩子上等 javac 把所有 class 编译出来后调用 AspectJ 编译器org.aspectj.tools.ajc.Main参数核心是-inpath/-d指向 class 输出目录原地编织-aspectpath传入完整 classpath让编译器能发现切面类。app 模块最后一行apply plugin: AspectjPlugin见 app/build.gradle把它激活插件本体发布到 repo/com/app/plugin/ 本地仓库供根构建文件引入。3.2 四个自带切面项目内置了四个切面全部放在 app/src/main/java/com/wangpos/s_mvp/aop/ 目录切面触发注解作用TimeLogAspectTimeLog自动打印方法耗时开关由BuildConfig.isTime控制CheckLoginAspectCheckLogin方法执行前校验登录状态MemoryCacheAspectMemoryCache方法结果写入 Lru 缓存TryCatchAspectTryCatch统一捕获异常防止崩溃以 TimeLogAspect.java 为例它声明Pointcut(execution(com.example.aspectj.TimeLog * *(..)))凡是被TimeLog标记的方法编织后会被around环绕——先记时间、执行原方法、再打印耗时。业务代码对此完全无感知。更多概念说明可参考 sources/aop.md。 这一步的意义切面逻辑被直接写进 class 字节码运行时零反射、零代理开销。四、阶段三Javassist 用 Transform 改写 class 字节码4.1 Transform 拦截 class 流JavassistTransform.groovy 实现了 AGP 的Transform接口getInputTypes()声明只接收CLASSES类型输入作用范围覆盖项目代码、子模块与外部库getScopes()。在transform()中它对每个 jar 和目录输入调用MyInject.injectDir(...)再把处理后的内容写入 output 目录交给后续 dex 步骤。4.2 到底注入了什么OkBus 事件总线MyInject.groovy 遍历com包下的每个 class用 javassist 的CtClass读取方法上的注解Bus事件方法、BusRegister、BusUnRegister。随后 BusHelper.groovy 做三件事在onCreate或自动生成里插入OkBus.getInstance().register(...)注册代码在onDestroy里插入unRegister(...)注销代码动态生成一个call(Message msg)方法内含switch(msg.what)事件分发逻辑并把类实现Event接口。也就是说你在方法上标一个Bus(事件ID)构建期就自动获得了注册 注销 分发全套代码而源码一行没动。这正是 README 所说的通过 javassist 修改字节码在不修改源码的情况下完成 AOP避免代码碎片化。⚠️ 常见坑CtClass用完后必须c.detach()否则 ClassPool 里残留旧代码增量构建会出怪问题源码中已明确注释。五、阶段四dex 打包一切归入 APK经过 Transform 处理后的 class 文件沿 AGP 标准流水线向下流动class被 Javassist 改写→ dx/d8 转换 → .dex → aapt 与资源/manifest 合并 → 签名 → APK对开发者来说这一步完全透明前三阶段的产物都已经是最终代码dex 只是格式转换。也正因为所有增强都发生在构建期运行时不需要额外引擎支撑。项目描述中提到的 Tinker 热修复则是这条链路的延伸由于业务代码集中在清晰的 MVP 分层见上方架构图补丁可以按模块粒度替换 dex 中的目标类配合 app/src/main/java/com/wangpos/s_mvp/ 下按功能分包的组织方式ui/login、ui/meizi、ui/wxnews等补丁范围更容易控制。六、一次构建的时间线速览把四个阶段串起来一次assembleDebug的增强链路是这样的javac 前libcomplier的 APT 处理器扫描注解用 JavaPoet 生成$$ViewBinder、InstanceFactory等新 java 文件加入本轮编译javac 后AspectjPlugin 的doLast触发 ajc把 4 个切面编织进全部 classTransform 阶段JavassistTransform 扫描 class为Bus类注入 OkBus 注册/注销/分发代码打包阶段AGP 将增强后的 class 转 dex、合资源、签名产出 APK。每一步都以上一步的输出为输入环环相扣——源码保持干净增强逻辑全部沉淀在构建体系里。七、上手建议如何快速验证 构建后查看app/build/generated/source/apt/能看到 APT 生成的真实 Java 源码 观察 Build 输出日志AspectjPlugin会打印Aspectj切片开始编织ClassJavassistTransform会打印耗时JavassistTransform cast : xx secs 给任意方法加上TimeLog重新构建运行后即可在 Logcat 的timeTAG 下看到耗时打印亲测整个链路生效 想理解切面原理优先阅读 sources/aop.md 与 TimeLogAspect.java 想理解任务调度等运行时能力可参考 SmartTaskManager 结构图八、总结S-MVP 的构建流水线是编译期魔法的教科书式组合APT JavaPoet负责从无到有生成代码消灭findViewById与 Presenter 创建样板AspectJ负责切面编织耗时日志、登录校验、缓存、异常捕获以注解形式一行接入Javassist Transform负责字节码级注入事件总线的注册/注销/分发全自动完成dex 打包将所有成果固化进 APK运行时零负担。理解这条 APT→AspectJ→Javassist→dex 的链路你也能在自己的项目中挑出最需要的环节复用——这正是编译期增强思想的精髓。✨赞分享【免费下载链接】S-MVP优化版MVP,使用注解泛型简化代码编写使用模块化协议方便维护APT过程使用注解解析器利用JavaPoet完成重复模块的编写利用ASpectGradlePlugin 完成横向AOP编程Javassist动态字节码注入Tinker实现热修复Retrofit实现优雅网络操作RxJava轻松玩转数据处理项目地址https://gitcode.com/gh_mirrors/smv/S-MVP点击查看免费下载相关推荐1 条命令解决百万行翻找难题用 xsv search 的 CSV 正则搜索把 2GB 运单干成 3 秒查询1 条命令解决百万行翻找难题用 xsv search 的 CSV 正则搜索把 2GB 运单干成 3 秒查询 凌晨两点客服弹过来一条消息昨天导出的运单里数据分析CLI数据工程揭秘Atmosphere固件打包从Package2到Package3的构建全流程揭秘Atmosphere固件打包从Package2到Package3的构建全流程 Atmosphere作为Nintendo Switch的定制固件其打包流程固件嵌入式操作系统系统编程xtool核心揭秘Darwin SDK 构建原理——如何从Xcode.xip打造iOS交叉编译环境xtool核心揭秘Darwin SDK 构建原理——如何从Xcode.xip打造iOS交叉编译环境 xtool 是一款跨平台 Xcode 替代品让开发者在开发工具CLI移动开发上一篇用原子距离约束引导折叠BioEmu-2接触条件Contact Conditioning特性实操技巧下一篇ThinkingCap-Qwen3.6-27B-OptiQ-4bit KV Cache 混合量化指南长上下文下的内存与速度优化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考