在Android项目中使用AspectJ

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载请表明出处:http://www.cnblogs.com/cavalier-/p/8888459.html

什么是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-initializationObject在构造函数中做的一些工作。-
initializationObject在构造函数中做的工作。-
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{
}

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

  • @Before: Advice, 也就是具体的插入点
  • execution:处理Join Point的类型,例如call、execution
  • (* android.app.Activity.on**(..)): 这个是最重要的表达式,第一个*表示返回值,*表示返回值为任意类型,后面这个就是典型的包名路径,其中可以包含 *来进行通配,几个 *没有区别。同时这里可以通过&&、||、!来进行条件组合。()代表这个方法的参数,你可以指定类型,例如android.os.Bundle,或者 (..) 这样来代表任意类型、任意个数的参数。
  • 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();@Overrideprotedcted void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);logTest();}@DebugTracepublic 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 Methodexecution (After)
}

Withincode

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

public class MainActivity extends AppCompatActivity{final String TAG = MainActivity.class.getSimpleName();@Orverideprotected 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

转载于:https://www.cnblogs.com/cavalier-/p/8888459.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368972.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LVM 逻辑卷 (logica volume manager)

逻辑卷轴管理员 (Logical Volume Manager) 想像一个情况,你在当初规划主机的时候将 /home 只给他 50G ,等到使用者众多之后导致这个 filesystem 不够大, 此时你能怎么作? 多数的朋友都是这样:再加一颗新硬盘&#xff0…

java中u怎么用_Java中interrupt的使用

通常我们会有这样的需求,即停止一个线程。在java的api中有stop、suspend等方法可以达到目的,但由于这些方法在使用上存在不安全性,会带来不好的副作用,不建议被使用。具体原因可以参考Why is Thread.stop deprecated。在本文中&am…

当Maven依赖插件位于

问题: 我们进行了一个集成测试,该测试创建了一个Spring ClassPathXmlApplicationContext ,同时这样做导致NoSuchMethodError爆炸。 事实证明,我们对Spring构件的依赖版本存在冲突。 这本身不是一个不寻常的问题-使用Maven依赖插件…

sql查询语句for xml path语法

【原地址】 for xml path作用:将多行的查询结果,根据某一些条件合并到一行。 例:现有一张表 执行下面语句 select Department,(SELECT Employee, FROM People b WHERE b.Departmenta.Department For XML Path()) Student from People as a g…

css高度已知,左右定宽,中间自适应三栏布局

css高度已知&#xff0c;左右定宽&#xff0c;中间自适应三栏布局&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale…

java使用impala存放多条sql_Impala基于内存的SQL引擎的详细介绍

数据存储使用相同的存储数据池都支持把数据存储于HDFS, HBase。元数据&#xff1a;两者使用相同的元数据SQL解释处理&#xff1a;比较相似都是通过词法分析生成执行计划。执行计划&#xff1a;Hive: 依赖于MapReduce执行框架&#xff0c;执行计划分成 map->shuffle->redu…

Android Studio打包以及Gradle配置构建

本文转载 郭霖公众号 https://mp.weixin.qq.com/s?__bizMzA5MzI3NjE2MA&mid2650241610&idx1&snb8af73f6c288b6617d9fe0ab3618118d&pass_ticketQK4j37kpmGNlsYcECWMb64HxKHEVJG5mSJubQEQguKI%3D 生成签名文件手动打包 首先生成签名文件&#xff0c;点击 Build…

去除inline-block间隙的几种方法

为什么会产生间隙&#xff1f; 由于编写代码时的美观和可读性&#xff0c;在代码中添加回车或空格而产生的间隙。 html代码&#xff1a; <ul class"container"><li></li><li></li><li></li><li></li><li&…

java重载方法math_Java语言程序设计(十二)Math数学类,方法重载及变量作用域...

1.重载方法上一篇文章用到的max方法只能用于int型数据类型&#xff0c;但是如果需要决定两个浮点数中哪个较大&#xff0c;解决方法是创建另一个方法名相同但参数不同的方法&#xff0c;代码如下&#xff1a;public static double max(double num1, double num2){if(num1>nu…

编码(转)

https://www.zhihu.com/question/28164512 关于编码和乱码的问题&#xff0c;我简单讲一下。 通常问这类问题的人是混淆了若干个不同的概念&#xff0c;并且他们自己也没有意识到自己混淆了这些概念的。 终端显示字符的编码&#xff08;windows下终端是cmd&#xff0c;linux下是…

Spring MVC:测试简介

测试是软件开发中最重要的部分之一。 井井有条的测试有助于使应用程序代码保持良好状态&#xff0c;并且处于工作状态。 有很多不同类型的测试和方法。 在本文中&#xff0c;我想对基于Spring MVC的应用程序进行单元测试进行介绍。 不要希望在这里阅读有关Spring MVC测试的全部…

yaml,json,ini这三种格式用来做配置文件优缺点

适合人类编写&#xff1a;ini > toml > yaml > json > xml > plist可以存储的数据复杂度&#xff1a;xml > yaml > toml ~ json ~ plist > ini 作者&#xff1a;赵扶摇链接&#xff1a;https://www.zhihu.com/question/41253282/answer/119857880来源&…

试验ConcurrentHashmap

我正在研究我最近的一个项目中的内存问题&#xff0c;该项目将数据保留在内存中以进行快速访问&#xff0c;但是应用程序的内存占用量非常大。 该应用程序大量使用CHM&#xff08;即Concurrenthashmap&#xff09; &#xff0c;因此&#xff0c;无需再费脑筋地猜测CHM是问题所…

CSS的position属性:relative和absolute

relative&#xff1a;是相对于自己来定位的&#xff0c;例如&#xff1a;#demo{position:relative;top:-50px;},这时#demo会在相对于它原来的位置上移50px。如果它之前的元素也为relative并有偏移&#xff0c;则两个偏移不想加&#xff0c;relative只在它原本所在位置上进行偏移…

java线程池任务失败_ThreadPoolExecutor线程池任务执行失败的时候会怎样

1. 任务执行失败时的处理逻辑1.1. WorkerWorker相当于线程池中的线程可以看到&#xff0c;Worker有几个重要的属性&#xff1a;thread &#xff1a; 这是Worker运行的线程&#xff0c;可以理解为一个Worker就是一个线程firstTask &#xff1a; 初始任务&#xff0c;可能为为n…

转:HttpModule与HttpHandler详解

ASP.NET对请求处理的过程&#xff1a;当请求一个*.aspx文件的时候&#xff0c;这个请求会被inetinfo.exe进程截获&#xff0c;它判断文件的后缀&#xff08;aspx&#xff09;之后&#xff0c;将这个请求转交给 ASPNET_ISAPI.dll&#xff0c;ASPNET_ISAPI.dll会通过http管道&…

bzoj 5248: [2018多省省队联测]一双木棋

Description 菲菲和牛牛在一块n行m列的棋盘上下棋&#xff0c;菲菲执黑棋先手&#xff0c;牛牛执白棋后手。棋局开始时&#xff0c;棋盘上没有任何棋子&#xff0c; 两人轮流在格子上落子&#xff0c;直到填满棋盘时结束。落子的规则是&#xff1a;一个格子可以落子当且仅当这个…

java 数据返回类_java返回数据工具类

1 importcom.qbskj.project.util.SpringUtils;23 /**4 * 消息5 *6 */7 public classMessage {89 /**10 * 类型11 */12 public enumType {1314 /**成功*/15 success,1617 /**警告*/18 warn,1920 /**错误*/21 error22 }2324 /**类型*/25 privateType type;2627 /**内容*/28 priva…

MOXy的对象图和动态JAXB

JAXB&#xff08;JSR-222&#xff09;使您可以轻松地将域类的实例转换为XML。 EclipseLink MOXy实现提供了一个称为Dynamic JAXB的扩展&#xff0c;在其中&#xff0c;您没有像真实类那样的映射实例&#xff0c;例如名为DynamicEntity的类。 您可以使用采用属性名称的get和set方…

Processing-Shader-Examples

https://github.com/genekogan/Processing-Shader-Examples 转载于:https://www.cnblogs.com/guochen/p/7681278.html