写点什么

一文读懂 AOP _ 你想要的最全面 AOP 方法探讨,kotlin 数据库框架

用户头像
Android架构
关注
发布于: 2021 年 11 月 05 日

如果说 OOP 是把问题划分到单个模块的话,那么 AOP 就是把涉及到众多模块的某一类问题进行统一管理。AOP 的目标是把这些功能集中起来,放到一个统一的地方来控制和管理。利用 AOP 思想,这样对业务逻辑的各个部分进行了隔离,从而降低业务逻辑各部分之间的耦合,提高程序的可重用性,提高开发效率。


OOP 与 AOP 的区别

  1. 面向目标不同:简单来说 OOP 是面向名词领域,AOP 面向动词领域。

  2. 思想结构不同:OOP 是纵向结构,AOP 是横向结构。

  3. 注重方面不同:OOP 注重业务逻辑单元的划分,AOP 偏重业务处理过程中的某个步骤或阶段。

OOP 与 AOP 的联系

两者之间是一个相互补充和完善的关系。



二、应用场景

那 AOP 既然这么有用,除了上面提到的打印日志场景,还有没有其他用处呢?


当然有!


只要系统的业务模块都需要引用通用模块,就可以使用 AOP。以下是一些常用的业务场景:

1. 参数校验和判空

系统之间在进行接口调用时,往往是有入参传递的,入参是接口业务逻辑实现的先决条件,有时入参的缺失或错误会导致业务逻辑的异常,大量的异常捕获无疑增加了接口实现的复杂度,也让代码显得雍肿冗长,因此提前对入参进行验证是有必要的,可以提前处理入参数据的异常,并封装好异常转化成结果对象返回给调用方,也让业务逻辑解耦变得独立。

2. Android API23+的权限控制

避免到处都是申请权限和处理权限的代码

3. 无痕埋点

4.

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


安全控制


比如全局的登录状态流程控制。

5. 日志记录

6. 事件防抖

防止 View 被连续点击触发多次事件

7. 性能统计

检测方法耗时其实已经有一些现成的工具,比如 trace view。痛点是这些工具使用起来都比较麻烦,效率低下,而且无法针对某一个块代码或者某个指定的 sdk 进行查看方法耗时。可以采用 AOP 思想对每个方法做一个切点,在执行之后打印方法耗时。

8. 事务处理

声明方法,为特定方法加上事务,指定情况下(比如抛出异常)回滚事务

9. 异常处理

替代防御性的 try-Catch。

10. 缓存

缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。

11. 软件破解

使用 Hook 修改软件的验证类的判断逻辑。

12. 热修复

AOP 可以让我们在执行一个方法的前插入另一个方法,运用这个思路,我们可以把有 bug 的方法替换成我们下发的新方法。



三、AOP 方法

本篇为入门篇,重在理解 AOP 思想和应用,辅助你快速进行 AOP 方法选型,所以 AOP 方法这块暂不会深入原理和术语。


Android AOP 常用的方法有 JNI HOOK 和 静态织入。

动态织入 Hook 方式

在运行期,目标类加载后,为接口动态生成代理类,将切面植入到代理类中。相对于静态 AOP 更加灵活。但切入的关注点需要实现接口。对系统有一点性能影响。


  1. Dexposed

  2. Xposed

  3. epic

  4. 在 native 层修改 java method 对应的 native 指针

动态字节码生成

  1. Cglib + Dexmaker


Cglib 是一个强大的,高性能的 Code 生成类库, 原理是在运行期间目标字节码加载后,通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。由于是通过子类来代理父类,因此不能代理被 final 字段修饰的方法。


但是 Cglib 有一个很致命的缺点:底层是采用著名的 ASM 字节码生成框架,使用字节码技术生成代理类,也就是通过操作字节码来生成的新的 .class 文件,而我们在 Android 中加载的是优化后的 .dex 文件,也就是说我们需要可以动态生成 .dex 文件代理类,因此 Cglib 不能在 Android 中直接使用。有大神根据 Dexmaker 框架(dex 代码生成工具)来仿照 Cglib 库动态生成 .dex 文件,实现了类似于 Cglib 的 AOP 的功能。详细的用法可参考:[将 cglib 动态代理思想带入 Android 开发](


)

静态织入方式

  • 在编译期织入,切面直接以字节码的形式编译到目标字节码文件中,,这要求使用特殊的 Java 编译器。

  • 在类装载期织入,这要求使用特殊的类装载器。


静态织入对系统无性能影响。但灵活性不够。


  1. APT

  2. AspectJ

  3. ASM

  4. Javassist

  5. DexMaker

  6. ASMDEX


这么多方法?有什么区别?

方法作用期比对

一图胜千言



AOP 是思想,上面的方法其实都是工具,只不过是插入时机和方式不同。


同:都可以织入逻辑,都体现了 AOP 思想


异:作用的时机不一样,且适用的注解的类型不一样。

方法优缺点、难点比对



四、常用的 AOP 方法介绍

业务中常用的 AOP 方式为静态织入,接下来详细介绍静态织入中最常用的三种方式:APT、AspectJ、Javassist。

1. APT

APT (Annotation Processing Tool )即注解处理器,是一种处理注解的工具,确切的说它是 javac 的一个工具,它用来在编译时扫描和处理注解。注解处理器以 Java 代码( 或者编译过的字节码)作为输入,生成 .java 文件作为输出。简单来说就是在编译期,通过注解生成 .java 文件。使用的 Annotation 类型是 SOURCE。


代表框架:DataBinding、Dagger2、ButterKnife、EventBus3、DBFlow、AndroidAnnotation

为什么这些框架注解实现 AOP 要使用 APT?

目前 Android 注解解析框架主要有两种实现方法,一种是运行期通过反射去解析当前类,注入相应要运行的方法。另一种是在编译期生成类的代理类,在运行期直接调用代理类的代理方法,APT 指的是后者。


如果不使用 APT 基于注解动态生成 java 代码,那么就需要在运行时使用反射或者动态代理,比如大名鼎鼎的 butterknife 之前就是在运行时反射处理注解,为我们实例化控件并添加事件,然而这种方法很大的一个缺点就是用了反射,导致 app 性能下降。所以后面 butterknife 改为 apt 的方式,可以留意到,butterknife 会在编译期间生成一个 XXX_ViewBinding.java。虽然 APT 增加了代码量,但是不再需要用反射,也就无损性能。

APT 的缺点改进

性能问题解决了,又带来新的问题了。我们在处理注解或元数据文件的时候,往往有自动生成源代码的需要。难道我们要手动拼接源代码吗?不不不,这不符合代码的优雅,JavaPoet 这个神器就是来解决这个问题的。

[JavaPoet](

)


JavaPoet 是 square 推出的开源 java 代码生成框架,提供 Java Api 生成 .java 源文件。这个框架功能非常有用,我们可以很方便的使用它根据注解、数据库模式、协议格式等来对应生成代码。通过这种自动化生成代码的方式,可以让我们用更加简洁优雅的方式要替代繁琐冗杂的重复工作。本质上就是用建造者模式来替代手工拼写源文件。


JavaPoet 详细用法可参考:[javapoet——让你从重复无聊的代码中解放出来](


)

2. AspectJ

目前最好、最方便、最火的 AOP 实现方式当属 AspectJ,它是一种几乎和 Java 完全一样的语言,而且完全兼容 Java。


但是在 Android 上集成 AspectJ 是比较复杂的。


我们需要使用 andorid-library gradle 插件在编译时做一些 hook。使用 AspectJ 的编译器(ajc,一个 java 编译器的扩展)对所有受 aspect 影响的类进行织入。在 gradle 的编译 task 中增加一些额外配置,使之能正确编译运行。等等等等……


有很多库帮助我们完成这些工作,可以方便快捷接入 AspectJ。

AspectJ 框架选型

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
一文读懂 AOP _ 你想要的最全面 AOP 方法探讨,kotlin数据库框架