AOP之AspectJ在Android实现无侵入埋点实践
Posted zcmain
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AOP之AspectJ在Android实现无侵入埋点实践相关的知识,希望对你有一定的参考价值。
什么是AOP
AOP(Aspect Oriented Programming)即面向切面编程,与我们常见的 OOP(Object Oriented Programming)面向对象编程都是不同的编程思想。
OOP 在业务处理过程中将实体和属性进行抽象封装,将功能模块化对象化,以获得更加清晰高效的逻辑单元划分。
AOP 是针对业务处理过程中的切面提取,他所面对的是处理过程中的某个步骤或阶段,对业务逻辑又进行了进一步的抽取,将多种业务逻辑中的公用部分抽取出来做成一种服务(比如日志记录,性能统计,安全验证等),从而实现代码复用。
如果说,OOP如果是把问题划分到单个模块的话,那么AOP就是把涉及到众多模块的某一类问题进行统一管理。
Aspectj
AspectJ是一个AOP框架,它扩展了Java语言,适用于 Java 平台。AspectJ 是在静态织入代码,即在编译期注入代码的。在开始之前,我们先看看需要了解的词汇:
Advice(通知): 是在切入点上织入的代码,其修饰的方法必须为 public,Advice 类型有 before、AfterReturning、after 、AfterThrowing 和 around分别表示在目标方法执行之前、执行后和完全替代目标方法执行的代码。Before、After、AfterReturning、AfterThrowing 四种类型修饰的方法返回值也必须为 void,Advice 需要使用 JoinPoint、JoinPointStaticPart、JoinPoint.EnclosingStaticPart 时,要在方法中声明为额外的参数,@Around 方法可以使用 ProceedingJoinPoint,用以调用 proceed() 方法,且返回值必须为Object。
Joint point(连接点): 程序中可能作为代码注入目标的特定的点和入口。
Pointcut(切入点): 具体的切入点,可以确定具体织入代码的地方,在何处注入一段特定代码的表达式。基本的 Pointcuts 是和 Join Point 相对应的(上图)。
Aspect(切面): Pointcut 和 Advice 的组合看做切面。
Weaving(织入): 注入代码(advices)到目标位置(joint points)的过程。
AndroidStudio上引入 AspectJ
在 android 上集成 AspectJ 比较麻烦,推荐使用 Github 上开源的 Gradle 插件 -- Android Aspectjx(https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx)。该插件是利用 Gradle 的 Transform API 在项目 class 文件打包成 dex 之前进入代码织入。
1、在项目根目录的build.gradle里依赖AspectJX
2、然后在 app 模块的 build.gradle 里配置插件
如果把 AspectJ 代码单独放到一个 library module 的话,library module 的gradle.build需要添加 compile 'org.aspectj:aspectjrt:1.8.+'
依赖。
下面是使用 android-aspectjx 插件需要注意的点:
android-aspectjx 插件是 使用在 application module 的插件,只能在编译 application module 的过程中织入代码。
AspectJ 的原理是在编译期注入代码,所以切面只能是项目代码、依赖的 jar 或 aar,不能注入 Android 平台 android.jar。例如,可以在 support 包的 Fragment 中注入代码,但是无法在 Activity 中注入代码,只能注入项目的继承自 Activity 的 XXActivity。
android-aspectjx 默认会遍历项目编译后所有的 .class 文件和依赖的第三方库去查找符合织入条件的切点,为了提升效率,可以加入过滤条件,具体见 Android Aspectjx 的文档。
使用AspectJ实现无侵入埋点
1、创建一个library并关联到app
2、配置Library gradle.build(独立的library使用AspectX需要配置compile 'org.aspectj:aspectjrt:1.8.+')
3、在app中创建一个登录和注册Activity,并实现最基本的登录注册按钮OnClick事件。
LoginActiviy
RegistActivity
很简单在登录和注册页面分别对Button和TextView控件OnClick事件下打印了一行日志,便于后续分析。
4、在之前我们创建的Library中创建一个切面类ClickAspect并使用@Aspect注解,定义PointCut具体的切入点如下:
5、编写我们的Advice方法并指定 Pointcut切入点要切入的代码
上面我们指定了Advice为@Around替代原来方法执行并指定PointCut为clickPointCut(),在原方法执行之前我们打印一些切到的信息包含:被切的目标方法名称、目标所在类、以及目标方法的参数集等等。紧接着我们调用
执行被切原方法,最后我们在被切的方法执行之后打印一串日志。
接下来我们运行程序,触发LoginActivity的登录按钮执行日志如下:
可见在我们点击登录按钮触发Button的OnClick事件被我们的切面拦截到,会进入到我们切面类的@Around注解的函数现行执行我们的代码,打印出当前被切方法的一些属性【2】可获取相应的被切方法名、所在类、以及方法的参数等等。然后调用了joinPoint.proceed()继续执行原方法可见日志【3】被打印原方法被执行,最后原方法执行结束继而执行我们后续的业务逻辑【4】。
同样我们在注册页面触发控件的OnClick都会被我们定义的切面函数捕捉进而做一些我们需要的操作。
基于AOP应用场景如动态权限管理、基于AOP的业务数据埋点、基于AOP的性能监测系统等等。以上AspectJ在Android上实现无侵入的实践,可见我们只需要自定切面及切点就可以捕捉到同类事件。并且可获取目标对象的属性。(无侵入埋点仅仅能获取一些目标对象基本数属等等如果需要捕捉我们自定义的数据应该如何处理呢???下一篇将会记录通过自定义注解和PointCut在不侵入业务代码逻辑层面实现我们对自定义数据的捕捉)。
以上是关于AOP之AspectJ在Android实现无侵入埋点实践的主要内容,如果未能解决你的问题,请参考以下文章