这里会带有 10 种 Java、Android 的 AOP 教程
- APT
- AspectJ
- Javassist
- CGLIB
- ByteBuddy
- JDK 动态代理
- ASM
- ASMDEX
- DexMaker
- Xposed
面向切面编程(Aspect-Oriented Programming),是 Java 开发中常见的编程方式,很多著名的开源框架都是基于 AOP 思想实现,比如 Spring、Retrofit、Mybatis 等,实现 AOP 的方式有很多种,主要分为三类:静态编译、编译期注入代码、动态编译,前两者都是在生成 jar、dex 包之前就完成代码处理,动态编译是在运行时实现,比如补丁就是动态编译实现。
示例图
.java.class.dex运行时
分类
我在这里总结了 10 种 AOP 的方式
| 名称 | 说明 | 支持 |
|---|---|---|
| APT | 静态编译 | Java、Android |
| AspectJ | 使用专门的编译器,在编译期插入代码 | Java、Android |
| Javassist | 动态编译与动态生成字节码 | Java、Android |
| CGLIB | 动态编译与动态生成字节码 | Java |
| ByteBuddy | 动态编译与动态生成字节码 | Java、Android |
| JDK 动态代理 | 动态代理 | Java、Android |
| ASM | 动态编译与动态生成字节码 | Java、Android |
| ASMDEX | 动态编译与动态生成字节码 | Android |
| DexMaker | 动态编译与动态生成字节码 | Android |
| Xposed | 需要 root 权限,在运行时插入字节码 | Android |
APT(Annotation Processing Tool)
APT 技术 Java 应用并不是特别广泛,但是在 Android 中是主要实现 AOP 的方式之一,通过注解实现在编译期间生成代码,执行效率高。
代表框架:ButterKnife、GRouter、AptPreferences
教程
Android APT(编译时代码生成)最佳实践
AspectJ
使用 AspectJ 编译器(ajc),在编译时期,在关键的的地方插入部分代码,处理相关逻辑,比如可以用于打印方法执行的效率,权限检查等,Spring 就使用了 AspectJ。在 Android 上的应用主要是做性能监控、基于注解的数据埋点等。
代表框架:Hugo、Spring
教程
利用 AspectJ 实现 Android 基于注解的无侵入埋点
TODO:所有带有注解的方法都通过经过一个拦截器,可以在拦截器实现打印信息,做埋点等,参考 Hugo,但是让用户自行试行,提供默认的拦截器。
CGLIB
CGLIB 是一个强大的,高性能,高质量的 Code 生成类库 ,是基于 ASM 封装,大名鼎鼎的 Hibernate 就是基于 CGLIB 实现,CGLIB 是一个应用非常广泛的 AOP 框架。
代表框架:Hibernate
+--- cglib:cglib:3.3.0| \--- org.ow2.asm:asm:7.1
教程
添加依赖
dependencies { implementation 'cglib:cglib:3.3.0'}
代码
public class CglibTest implements MethodInterceptor { public static void main(String[] args) { User user = (User) new CglibTest().getProxy(User.class); user.setId(1); user.getId(); } public Enhancer enhancer = new Enhancer(); private Object getProxy(Class clazz) { enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("执行开始:" + method); Object result = proxy.invokeSuper(obj, args); System.out.println("执行结束:" + method); return result; } public static class User { private int id; public int getId() {return id;} public void setId(int id) {this.id = id;} }}
结果
执行开始:public void com.thejoyrun.aptpreferences.CglibTest$User.setId(int)执行结束:public void com.thejoyrun.aptpreferences.CglibTest$User.setId(int)执行开始:public int com.thejoyrun.aptpreferences.CglibTest$User.getId()执行结束:public int com.thejoyrun.aptpreferences.CglibTest$User.getId()
ByteBuddy
Byte Buddy 是一个运行时动态生成字节码的库,它是依赖 Java 虚拟机,由于 Android 的字节码和 Java 不同,也提供了 Android 的支持包,大名鼎鼎的测试框架 Mockito 就是基于 ByteBuddy 实现,Mockito3 也正式支持在 Android 运行时环境使用,但是包大小为 3.3MB,建议只在 debug 环境下使用。
api 'net.bytebuddy:byte-buddy:1.10.1'api 'net.bytebuddy:byte-buddy-android:1.10.1'
代表框架:AopPreferences、Mockito
教程
添加依赖
dependencies { implementation 'net.bytebuddy:byte-buddy:1.10.1' // implementation 'net.bytebuddy:byte-buddy-android:1.10.1'}
代码
public class ByteBuddyTest { public static void main(String[] args) { User user = new ByteBuddyTest().getProxy(User.class); user.setId(1); user.getId(); } private T getProxy(Class clazz) { Class
关注
打赏
