android aspectj 参数,在Android项目中使用AspectJ

什么是AOP

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

AspectJ

AspectJ其实是对AOP编程的实践,目前还有不少的AOP实现,如ASMDex,但笔者选用的是AspectJ。git

在Android项目中使用AspectJ

若是使用原生AspectJ在项目中配置会很是麻烦,在GitHub上有个开源的SDK gradle_plugin_android_aspectjx基于gradle配置便可。github

接入说明

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

AspectJ 之 Join Points介绍

Join Points在AspectJ中是关键的概念。Join Points能够看作是程序运行时的一个执行点,好比:一个函数的调用能够看作是个Join Points,至关于代码切入点。但在AspectJ中,只有下面几种执行点是认为是Join Points:app

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的方法。ide

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();

@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*(..))") 整个表达式能够分为五个部分:

execution()是表达式主体

第一个*号表明返回类型,*号表明全部的类型。

包名 表示须要拦截的包名,这里使用*.表明匹配全部的包名。

第二个*号表示类名,后面跟.MainActivity是指具体的类名叫MainActivity。

*(..) 最后这个星号表示方法名,+.表明具体的函数名,*号通配符,包括括弧号里面表示方法的参数,两个dot表明任意参数。

遇到的错误

如下错误可使用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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值