此文已由作者徐铭阳授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
提到AOP就不得不提到我们最常见的OOP,他们的不同之处在于OOP是将模块功能封装模块化对象化,而AOP呢?AOP是Aspect Oriented Programming的缩写,顾名思义:面向切面编程。
对后台开发而言AOP在Spring种已经运用的非常广泛了,它主要用于不想侵入原有代码场景,例如一些SDK需要无侵入在宿主中植入代码,大概会用于日志埋点、性能监控、动态权限等等相关问题,将那些影响了多个类的公共行为封装到一个可重用模块。对Android客户端来说也有一些像ButterKnife,AndroidAnnotation等开源框架采用的AOP的思想,由于最近在做日志以及埋点相关的内容,对Android端采用AOP做了一些实践
网上大概搜了下,在Android端比较常用的也比较流行的就是AspectJ了,当然还有很多其他的。AspectJ支持编译期间和加载代码时代码注入,可以理解是为一种hook技术。官网地址为http://www.eclipse.org/aspectj/,AspectJ官方是这么定义的:
a seamless aspect-oriented extension to the Javatm programming language,
Java platform compatible
easy to learn and use
AspectJ可以做什么呢官网是这么说的
clean modularization of crosscutting concerns, such as error checking and handling, synchronization, context-sensitive behavior, performance optimizations, monitoring and logging, debugging support, and multi-object protocols
大概翻译下就是对横切关注点进行清晰的模块化区分,如错误检查和处理、同步、上下文敏感行为、性能优化、监控和日志记录以及调试支持和多对象协议
官网关于AOP能做什么已经很清晰了,它几乎是一种和java完全一样的语言,完全兼容java,而且除了AspectJ语言外,AspectJ加上对应的AspectJ注解即可支持原生java。如果我们无侵入原有代码场景,那么AspectJ是一个非常好的选择
关于AOP有几个术语,几乎每个涉及AOP的文章都要提到即:
Joint Points,怎么解释呢?可以理解为程序运行时的一些执行点,如 中M这边NTlog.i(),i的执行可以是一个JPoint,调用i的方法也可以认为是一个JPoint,变量的设置也可以是JPoint,for循环也可以是一个JPoint,一个程序中很多地方都可以看做是JPoint
PointCuts, 又是很难去解释的一个词,举个栗子吧,都知道在android中每个页面是一个Activity或者Fragment,Actiivty中可能有很多内容,各种变量各种方法,肯定不是所有的变量和方法都是我们所关注的,在做埋点过程中你会发现可能只有几个生命周期方法是入onCreate()、onResume()、onPause()、onDestroy()才是我们需要关注的,PointCuts提供了一种方法使得开发者可以从很多JPoints中选择自己感兴趣的JPoint,PointCut有一套自己的语法涉及到的东西有很多,也有很多高级玩法有兴趣的可以了解下,对我现在来说基本玩法就够了
Advice,那么真实的插入我们设置代码就是Advice了,可以这么理解,Advice是一种Hook,如下表格中列出了所有的Advice类型
Aspect,一个包含Joint Point、PointCut、Advice的类可以就可以称为Aspect了
Android中AscpectJ主要是对java字节码进行处理,AspectJ如果要在Andorid中使用,需要在gradle文件中加入编译脚本,用于将SDK和源代码识别出来并注入
以下是我写的关于在Activity生命周期运用AspectJ的例子,核心代码如下:
注释已经差不多比较清楚了,首先我们需要声明切点,根据不同的需求选择不同时机调用对应的Advice。 大家可以看下生成的class的代码:
基本上关于AspectJ的应用就差不多完事了,但是如果就此打住,其实也能满足所有的需求,鉴于之前踩过的一些坑,该方式修改了class文件,而且一般涉及到使用这种方式的都是framework中,出问题的话基本上就会影响所有的页面,使用AspectJ可能不太好查问题,另一方面每个切点都会生成一个class,其实android对包大小的要求还是挺严格的,将来切点比较多的情况下难免会有很多class文件会对包大小产生一定的影响。考虑到这一点,就是下一步的工作了,也是最关键的部分了
通过FrameworkCutManager统一管理所有切面,在ActivityBase各个生命周期方法中注入,统一管理,一方面减少了依赖framework不用处理业务逻辑,另一方面framework也会比较干净,上层业务可以实现Advice在切点方法中注入代码,依赖解耦
如有问题欢迎指正交流
网易云免费体验馆,0成本体验20+款云产品!
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 深入浅出“跨视图粒度计算”--1、理解数据的粒度