美文网首页
Android Aop编程总结之二AspectJ

Android Aop编程总结之二AspectJ

作者: 大鹏的鹏 | 来源:发表于2019-04-23 17:59 被阅读0次

一.AspectJ概念。

AspectJ实际上是对AOP编程思想的一个实践,AOP虽然是一种思想,但就好像OOP中的Java一样,一些先行者也开发了一套语言来支持AOP。目前用得比较火的就是AspectJ了,它是一种几乎和Java完全一样的语言,而且完全兼容Java。当然,除了使用AspectJ特殊的语言外,AspectJ还支持原生的Java,只要加上对应的AspectJ注解就好。所以,使用AspectJ有两种方法:

  • 完全使用AspectJ的语言。这语言一点也不难,和Java几乎一样,也能在AspectJ中调用Java的任何类库。AspectJ只是多了一些关键词罢了。
  • 或者使用纯Java语言开发,然后使用AspectJ注解,简称@AspectJ。

二.配置Android studio支持AspectJ。

如果要在Android Studio中使用AspectJ,需要在项目的build里面进行一大堆配置,为了方便快捷,推荐使用沪江的gradle_plugin_android_aspectjx

步骤一:
在project级别的build.gradle中添加:

buildscript {
  ...
    dependencies {
     ...
        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
    }
}

步骤二:
在module级别的build.gradle中添加:

apply plugin: 'android-aspectjx'
//或者这样也可以
apply plugin: 'com.hujiang.android-aspectjx'

三.AspectJ 简单使用:

步骤一:
创建一个FirstActivity ,只有基本的生命周期方法。

public class FirstActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }
}

步骤二:
编写一个AspectJ类。这个类要做的事情是告诉ACJ编译器,要在MainActivity中的每个方法前面打印一行log,输出当前执行的是哪个方法,

@Aspect// 告诉ACJ编译器这是个AspectJ类
public class TraceAspect {
    private static final String TAG = "TraceAspect";

    @Pointcut("execution(* com.yousheng.aspectjdemo.FirstActivity.**(..))")// 注意*号后面必须有空格
    public void executeAspectJ() {

    }

    @Before("executeAspectJ()")
    public void beforeAspectJ(JoinPoint joinPoint) throws Throwable {
        Log.d(TAG, "injected -> " + joinPoint.toShortString());
    }
}

步骤三:
查看这段代码执行的结果

  D/TraceAspect: injected -> execution(FirstActivity.onCreate(..))
  D/TraceAspect: injected -> execution(FirstActivity.onStart())
  D/TraceAspect: injected -> execution(FirstActivity.onResume())

分析: 通过上面例子我们可以看到,我们在FirstActivity 的onCreate(),onStart(),onResume()中并未写任何代码,但是在执行这些方法的时候却输出了Log信息。这说明我们的切面成功的进行了切入。
而且在上面引出了@AspectJoin Points@Pointcut@Around这样的概念, 下面我们分别对这些进行解释。

  • @Aspect 修饰一个类,作用是把当前类标识为一个切面供容器读取,切面是切入点和通知的集合。

  • Join Points 程序运行执行点,比如上面的execution就是其中的一种类型,还有Call类型等 ,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 的内容 -
  • Pointcut 选出我们需要的Join Points,是指那些通过使用一些特定的表达式过滤出来的想要切入Advice的连接点。如
 @Pointcut("execution(@com.yousheng.aspectjdemo.SingleClick * *(..))")// 切点表达式
private void dataAccessOperation() {} // 切点前面的这个方法必须无返回值.

execution指的是类型,也就是以方法执行时为切点,触发Aspect类。而execution里面的字符串是触发条件,也是具体的切点。com.yousheng.aspectjdemo.annotation.SingleClick 指的是包名+对应的类名,第一个* 指的是返回值为任意类型,第二个*指的是方法名为任意类型或者是构造器的话使用new代替,(..)指的是任意类型的参数,参数用的是正则匹配语法。

Join Points和Pointcut的区别
Join point 就是菜单上的选项,Pointcut就是你选的菜。Join point 你只是你切面中可以切的那些方法,一旦你选择了要切哪些方法,那就是Pointcut。

也就是说,所有在你程序中可以被调用的方法都是Join point. 使用Pointcut 表达式,那些匹配的方法,才叫Pointcut。所以你根本不用关心Join point。比如你有10个方法,你只想切2个方法,那么那10个方法就是Join point, 2个方法就是Pointcut。

所有的方法都可以认为是 joinpoint, 但是我们并不希望在所有的方法上都添加 Advice, 而 pointcut 的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述) 来匹配joinpoint, 给满足规则的 joinpoint 添加 Advice.

  • Advice 就是我们插入的代码可以以何种方式插入,常见的有Before 还有 After、Around。
名称 描述
Before 在方法执行之前执行要插入的代码
After 在方法执行之后执行要插入的代码
Around 在方法前后各插入代码,他包含了 Before和 After 的全部功能
  • Weaving 编织:主要是在编译期使用AJC将切面的代码注入到目标中, 并生成出代码混合过的.class的过程.

execution()是最常用的切点函数,其语法如下所示:
例如下面这段语法:
@Around(“execution(* ..MainActivity+.on(..))")
整个表达式可以分为五个部分:

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

结合注解的例子:
第一步:

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface Transaction {
}

第二步:

@Aspect
public class TransactionAspect {
    private static final String TAG = "TransactionAspect";
    private static final String TRANSACTION_METHOD =
            "execution(@com.goach.myaspectj.annotation.Transaction * *(..))";
    @Pointcut(TRANSACTION_METHOD)
    public void transactionMethod(){}

    @Around("transactionMethod()")
    public void addTransaction(ProceedingJoinPoint joinPoint){
        Log.d(TAG,"开始事务....");
        try {
            joinPoint.proceed();//执行原方法
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        Log.d(TAG,"结束事务....");
    }
}

第三步:

@Transaction//加上注解
public void hello(View view){
        Log.d(TAG,"hello aspectJ");
}

执行结果 :

   @Around("transactionMethod()")
    public void addTransaction(ProceedingJoinPoint joinPoint){
         MethodSignature methodSignature = (MethodSignature) point.getSignature();
// 拿到注解        
BehaviorTrace behaviorTrace = methodSignature.getMethod().getAnnotation(BehaviorTrace.class); 
// 类名
        String className = methodSignature.getDeclaringType().getSimpleName();
        // 方法名
        String methodName = methodSignature.getName();
    }

四.AspectJ主要应用场景

  • 数据统计
  • 日志记录
  • 用户行为统计
  • 应用性能统计
  • 数据校验
  • 行为拦截
  • 无侵入的在宿主中插入一些代码,
  • 做日志埋点
  • 性能监控
  • 动态权限控制
  • 代码调试

AOP之AspectJ在Android中的应用
AndroidStudio 配置 AspectJ 环境实现AOP
Spring 之AOP AspectJ切入点语法详解(最全面、最详细。)
AOP AspectJ 字节码 示例 Hugo MD
AOP之@AspectJ技术原理详解
关于AspectJ,你需要知道的一切

相关文章

网友评论

      本文标题:Android Aop编程总结之二AspectJ

      本文链接:https://www.haomeiwen.com/subject/ozlbgqtx.html