在Android项目中使用AspectJ的方法

什么是AOP

AOP是 Aspect Oriented Programming 的缩写,即面向切面编程,和平常遇到的面向对象OOP编程不一样的是,OOP是将功能模块化对象化,AOP是针对同一类的问题统一化处理。例如做日志埋点,性能监控,动态权限控制等。

AspectJ

AspectJ实际上是对AOP编程的实践,目前还有很多的AOP实现,如ASMDex,但笔者选用的是AspectJ。

在Android项目中使用AspectJ

如果使用原生AspectJ在项目中配置会非常麻烦,在GitHub上有个开源的SDK gradle_plugin_android_aspectjx基于gradle配置即可。

接入说明

请自行查看开源项目中的接入配置过程

AspectJ 之 Join Points介绍

Join Points在AspectJ中是关键的概念。Join Points可以看做是程序运行时的一个执行点,比如:一个函数的调用可以看做是个Join Points,相当于代码切入点。但在AspectJ中,只有下面几种执行点是认为是Join Points:

Join Points 说明 实例
method call 函数调用 比如调用Log.e(),这是一个个Join Point
method execution 函数执行 比如Log.e()的执行内部,是一处Join Points。注意这里是函数内部
constructor call 构造函数调用 和method call 类似
constructor execution 构造函数执行 和method execution 类似
field get 获取某个变量 比如读取DemoActivity.debug成员
field set 设置某个变量 比如设置DemoActivity.debug成员
pre-initialization Object在构造函数中做的一些工作。 -
initialization Object在构造函数中做的工作。 -
static initialization 类初始化 比如类的static{}
handler 异常处理 比如try catch 中,对应catch内的执行
advice execution 这个是AspectJ 的内容 -

Pointcuts 介绍

一个程序会有多个Join Points,即使同一个函数,也还分为call 和 execution 类型的Join Points,但并不是所有的Join Points 都是我们关心的,Pointcuts 就是提供一种使得开发者能够值选择所需的JoinPoints的方法。

Advice

Advice就是我们插入的代码可以以何种方式插入,有Before 还有 After、Around。
下面看个例子:

@Before(“execution(* android.app.Activity.on**(..)))”)
public void onActivityMethodBefore(JoinPoint joinPoint) throws Throwable{
}

这里会分成好几个部分,我们依次来看:

  1. @Before: Advice, 也就是具体的插入点
  2. execution:处理Join Point的类型,例如call、execution
  3. (* android.app.Activity.on**(..)): 这个是最重要的表达式,第一个*表示返回值,*表示返回值为任意类型,后面这个就是典型的包名路径,其中可以包含 *来进行通配,几个 *没有区别。同时这里可以通过&&、||、!来进行条件组合。()代表这个方法的参数,你可以指定类型,例如android.os.Bundle,或者 (..) 这样来代表任意类型、任意个数的参数。
  4. public void onActivityMehodBefore: 实际切入的代码。

Before 和 After 其实还是很好理解的,也就是在Pointcuts之前和之后,插入代码,那么Android呢,从字面含义上来讲,也就是在方法前后各插入代码,他包含了 Before和 After 的全部功能,代码如下:

@(“execution(* com.xys.aspectjxdemo.MainActivity.testAOP()))”)
public void onActivityMethodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
String key = proceedingJoinPoint.getSignature().toString();
Log.d(TAG,”onActivityMethodAroundFirst:”+key);
proceedingJoinPoint.proceed();
Log.d(TAG,”onActivityMethodAroundSecond:”+key);
}

以上代码中,proceedingJoinPoint.proceed()代表执行原始的方法,在这之前、之后,都可以进行各种逻辑处理。

自定义Pointcuts

自定义Pointcuts可以让我们更加精准的切入一个或多个指定的切入点。

首先我们要定义一个注解类

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface DebugTrace {
}

在需要插入代码的地方加入这个注解,例如在MainActivity中加入:

public class MainActivity extends AppCompatActivity{
final String TAG = MainActivity.class.getSimpleName();

@Override
protedcted void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
logTest();
}

@DebugTrace
public void logTest(){
Log.e(TAG,”log test");
}
}

最后创建切入代码

@Pointcut(“execution(@com.kun.aspectjtest.aspect.DebugTrace * *..*.*(..))”)
public void DebugTraceMethod(){}

@Before(“DebugTraceMethod()”)
public void beforeDebugTraceMethod(JoinPoint joinPoint) throws Throwable{
String key = joinPoint.getSignature().toString();
Log.e(TAG, “beforeDebugTraceMethod:”+key);
}

Call

在AspectJ的切入点表达式中,我们前面都是使用的execution,实际上还有一种类型—call,那么这两种语法有什么区别呢?对call来说:

Call (Before)
Pointcut{
Pointcut Method
}
Call (After)

对Execution来说:

Pointcut{
execution (Before)
Pointcut Method
execution (After)
}

Withincode

这个语法通常来进行一些切入点条件的过滤,作更加精确的切入控制,如下:

public class MainActivity extends AppCompatActivity{
final String TAG = MainActivity.class.getSimpleName();

@Orveride
protected void onCreate(Bundle savedInstanceState){
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
aspectJ1();
aspectJ2();
aspectJ3();
}
public void aspectJTest(){
Log.e(TAG,”execute aspectJTest");
}

public void aspectJ1(){
aspectJTest();
}
public void aspectJ2(){
aspectJTest();

}
public void aspectJ3(){
aspectJTest();
}
}

aspectJ1(),aspectJ2(),aspectJ3()都调用了aspectJTest方法,但只想在aspectJ2调用aspectJTest时插入代码,这个时候就需要使用到Pointcut和withcode组合的方式,来精确定位切入点。

@Pointcut(“(call(* *..aspectJTest()))&&withincode(* *..aspectJ2())”)
public void invokeAspectJTestInAspectJ2(){
}

@Before(“invokeAspectJTestInAspectJ2()”)
public void beforeInvokeaspectJTestInAspectJ2(JoinPoint joinPoint) throws Throwable{
Log.e(TAG,”method:”+getMethodName(joinPoint).getName());
}

private MethodSignature getMethodName(JoinPoint joinPoint){
if(joinPoint == null) return null;
return (MethodSignature) joinPoint.getSignature();
}

execution 语法

execution()是最常用的切点函数,其语法如下所示:

例如下面这段语法:@Around(“execution(* *..MainActivity+.on*(..))")

整个表达式可以分为五个部分:
1.execution()是表达式主体
2.第一个*号代表返回类型,*号代表所有的类型。
3.包名 表示需要拦截的包名,这里使用*.代表匹配所有的包名。
4.第二个*号表示类名,后面跟.MainActivity是指具体的类名叫MainActivity。
5.*(..) 最后这个星号表示方法名,+.代表具体的函数名,*号通配符,包括括弧号里面表示方法的参数,两个dot代表任意参数。

遇到的错误

1.以下错误可以使用gradle2.2.3解决,由于目前还不适配gradle3.0导致的

Error:Execution failed for task ':app:transformClassesWithDexBuilderForDebug'.
> Unexpected scopes found in folder '/Users/ram/WorkSpace/AndroidWorkSpace/MyDemo/app/build/intermediates/transforms/AspectTransform/debug'. Required: PROJECT, SUB_PROJECTS, EXTERNAL_LIBRARIES. Found: EXTERNAL_LIBRARIES, PROJECT, PROJECT_LOCAL_DEPS, SUB_PROJECTS, SUB_PROJECTS_LOCAL_DEPS

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • AndroidStudio 配置 AspectJ 环境实现AOP的方法
  • Android AOP框架AspectJ使用详解
  • Android中使用AspectJ详解
(0)

相关推荐

  • Android AOP框架AspectJ使用详解

    前言 之前了解过android的AOP框架,用法主要用来打日志:现在有一个需求需要函数在新线程中执行,并且函数主体执行完之后,在UI线程返回结果.想到手写的话,每次都要new Thread的操作,比较麻烦:因此就尝试用注解的方法解决这个问题. AspectJ的使用核心就是它的编译器,它就做了一件事,将AspectJ的代码在编译期插入目标程序当中,运行时跟在其它地方没什么两样,因此要使用它最关键的就是使用它的编译器去编译代码ajc.ajc会构建目标程序与AspectJ代码的联系,在编译期将Aspe

  • Android中使用AspectJ详解

    什么是AOP AOP是Aspect Oriented Programming的缩写,即『面向切面编程』.它和我们平时接触到的OOP都是编程的不同思想,OOP,即『面向对象编程』,它提倡的是将功能模块化,对象化,而AOP的思想,则不太一样,它提倡的是针对同一类问题的统一处理,当然,我们在实际编程过程中,不可能单纯的安装AOP或者OOP的思想来编程,很多时候,可能会混合多种编程思想,大家也不必要纠结该使用哪种思想,取百家之长,才是正道. 那么AOP这种编程思想有什么用呢,一般来说,主要用于不想侵入原

  • AndroidStudio 配置 AspectJ 环境实现AOP的方法

    昨天看了一段android配置aspectj实现AOP的直播视频,就试着自己配置了一下,可能是因为我自己的AndroidStudio环境的问题,碰到了不少的坑(其实还是因为对gradle理解的不多),但总归是配置好了,就分享一下. 试了两种方式,不过项目下的build.gradle,没什么变化,直接看一下代码吧: build.gradle(项目下) buildscript { ext { //android appcompat支持库版本 androidSupportVersion = '26.1

  • 在Android项目中使用AspectJ的方法

    什么是AOP AOP是 Aspect Oriented Programming 的缩写,即面向切面编程,和平常遇到的面向对象OOP编程不一样的是,OOP是将功能模块化对象化,AOP是针对同一类的问题统一化处理.例如做日志埋点,性能监控,动态权限控制等. AspectJ AspectJ实际上是对AOP编程的实践,目前还有很多的AOP实现,如ASMDex,但笔者选用的是AspectJ. 在Android项目中使用AspectJ 如果使用原生AspectJ在项目中配置会非常麻烦,在GitHub上有个开

  • 在Android项目中使用AspectJ的详细攻詻

    AOP 全称"Aspect Oriented Programming",面向切面编程,由于面向对象的思想要求高内聚,低耦合的风格,使模块代码间的可见性变差,对于埋点,日志输出等需求,就会变的十分复杂,如果手动编写代码,入侵性很大,不利于扩展,AOP应运而生. AspectJ AspectJ实际上是对AOP编程的实践,目前还有很多的AOP实现,如ASMDex,但笔者选用的是AspectJ. 使用场景 当我们需要在某个方法运行前和运行后做一些处理时,便可使用AOP技术.具体有: 统计埋点

  • Android项目中引入aar包的正确方法介绍

    目录 一.Android项目中引入aar包的方法 二.Android导入jar包 补充:Android 引入aar包后,应用图标改变了 总结 一.Android项目中引入aar包的方法 我在使用高德地图的sdk的时候,选择用引入aar包的方式,然后按照网上的教程引入.但是一直报错,我很懵逼. 这是教程 1.在build.gradle中的android{}外层添加 repositories { flatDir { dirs 'libs' } } 2.将aar包添加到项目的libs文件夹下 3.在d

  • Android Studio中导入module的方法(简单版)

    1.把要导入成Mudle的项目修改成符合Library的格式 修改该项目中bulid.gradle文件中第一行代码 把 apply plugin: 'com.android.application' 修改为 apply plugin: 'com.android.library' 然后,修改AndroidManifiest.xml文件中配置信息,此处主要是把原来配置的项目Style等配置以及MainActivity配置删除,这样处理是为了防止重复.以下以一个我的Moudle文件的AndroidMa

  • Android编程中黑名单的实现方法

    本文实例讲述了Android编程中黑名单的实现方法.分享给大家供大家参考,具体如下: 说明:由于挂断电话android   api不是对外开放的,所以需要使用反射的方法得到拨打电话的服务. 1.将android源代码中的"aidl"文件拷贝到项目中 这样项目中会生成两个包:android.telephony:此包中文件为:NeighboringCellInfo.aidl com.android.internal.telephony;此包中文件为:ITelephony.aidl 2.通过

  • 如何在原有Android项目中快速集成React Native详解

    前言 RN经过一段时间发展,已经有充分数量的人尝试过了,就我身边就有几批,褒贬也不一: ① 做UI快 ② 还是有很多限制,不如原生Native ③ 入门简单,能让前端快速开发App ④ iOS&Android大部分代码通用 ⑤ code-push能做热更新,但是用不好依旧坑 ...... 在得到一些信息后,可以看出,要用RN高效率的做出比较不错的App是有可能的,单看投入度与最初设计是否合理,而且现在关于React Native的各种文档是相当丰富的,所以这个阶段想切入RN可能是一个不错的选择.

  • SpringBoot项目中使用AOP的方法

    本文介绍了SpringBoot项目中使用AOP的方法,分享给大家,具体如下: 1.概述 将通用的逻辑用AOP技术实现可以极大的简化程序的编写,例如验签.鉴权等.Spring的声明式事务也是通过AOP技术实现的. 具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-aop Spring的AOP技术主要有4个核心概念: Pointcut: 切点,用于定义哪个方法会被拦截,例如 execution(* cn.sp

  • Android项目中实体类entity的作用详解

    估计很多入门安卓的朋友对entity很困惑,为什么要写实体类?有什么用?写来干什么? 对于实体类的理解我入门的时候也是困惑了好久,后面用多了才慢慢理解,这篇博客就当复习和笔记. Java中entity(实体类)的写法规范 在日常的Java项目开发中,entity(实体类)是必不可少的,它们一般都有很多的属性,并有相应的setter和getter方法.entity(实体类)的作用一般是和数据表做映射.所以快速写出规范的entity(实体类)是java开发中一项必不可少的技能. 在项目中写实体类一般

  • Android项目中gradle的执行流程

    目录 gradle文件执行流程 自定义gradle文件的导入方法 gradle中定义的变量如何被java代码使用 gradle文件执行流程 做过Android开发的同学都知道 ,Android项目中存在三个gradle文件,那你是否知道他们的执行流程呢?请看下面这张图: 为了验证结论 的正确性,我们采用输出字符串的验证方式: 输出结果如下: 自定义gradle文件的导入方法 上面所阐述的三个 gradle 文件是由系统来管理的,那我们能创建gradle文件吗?答案是肯定的. 那我们创建的 gra

  • gulp教程_从入门到项目中快速上手使用方法

    gulp是什么? gulp 是基于 node 实现 Web 前端自动化开发的工具,利用它能够极大的提高开发效率.在 Web 前端开发工作中有很多"重复工作",比如压缩CSS/JS文件.而这些工作都是有规律的.找到这些规律,并编写 gulp 配置代码,让 gulp 自动执行这些"重复工作" 一.安装gulp与压缩js文件 命令: npm install gulp -g npm install gulp --save-dev 初始化项目package.json的配置:n

随机推荐