AOP实现检测方法耗时

2018-08-20  本文已影响0人  文子产品笔记

写文章之前首先得解释下什么是AOP,AOP(Aspect-Oriented Programming,面向切面编程),它是对OOP(Object-Oriented Programing,面向对象编程)的一种补充,传统的OOP针对业务处理过程的实体及其属性和行为进行高度抽象封装,每个类都是一个独立体,实现特有的功能,互不干扰。而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

AOP主要功能:

日志记录,性能统计,安全控制,事务处理,异常处理等等。

AOP优点:

1,每个事物逻辑位于一个位置,代码不分散,便于维护和升级

2,业务模块更简洁,只包含核心业务代码

今天这边实现的就是一个日志记录切面,比如在某个页面展现时候特别卡顿,延时比较长,我们可能需要测试这个页面中所有方法耗时时间,找出耗时的方法然后做一些异步操作。

需要用到的第三方.jar包:aspectjrt.jar,需要引用到gradle中。

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

也就是说AspectJ编译器在代码的编译阶段植入Pointcut的内容 ,它的性能比较好。

首先,我们自定义一个注解,这个注解是我们暴露在外面的调用的,外面只需要调用这个注解,就会对这个方法进行编译植入我们希望进行切面的操作。

/**

* 用来标识性能监测

*/

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface BehaviorTrace {

    String value() default "";

    String value2() default "";

}

我们在定义一个注解的过程中我们一般需要知道的几个知识点:

1,我们的注解和类一样,使用@interface进行申明

2,指定的注解的运行时机@Retention(RetentionPolicy.RUNTIME),这里我们指定是在运行时,有如下几种参

FF0B337D-2B62-4396-B3B6-299E9C78D4BD.png

3,指定注解的类型@Target(ElementType.FIELD),它有如下几种参数:

6662CDEB-8CB8-4F1A-B1D9-CC276A20F964.png

然后就是定义我们的注解接收的参数,它可以接受基本的数据类型,String,数组等…

其次,我们定义一个类,这个类需要实现@Aspect注解,它的作用是把当前类标识为一个切面可供容器读取。这个类中我们做两个操作,一个是定义AOP切面规则,另一个是对切面内容的处理。

/**

* Created by 48608 on 2018/3/5.

*/

@Aspect

public class BehaviorTraceAspect {

    //定义切面的规则

    //1.就在原来应用中哪些注释的地方放到当前切面进行处理

    //execution(注释名  注释用的地方)

    //com.dcw.aop_aspect.annotation.BehaviorTrace * *(..)代表的是任意定义了BehaviorTrace注解的方法都执行这个切面方法

    @Pointcut("execution(@com.dcw.aop_aspect.annotation.BehaviorTrace * *(..))")

    public void methodAnnotatedWithBehaviorTrace(){}

    //2.对进入切面的内容如何处理

    //advice

    //@Before()  在切入点之前运行

    //@After()  在切入点之后运行

    //@Around()  在切入点前后都运行

    //围绕methodAnnotatedWithBehaviorTrace()方法进行切面操作

    @Around("methodAnnotatedWithBehaviorTrace()")

    public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable{

        MethodSignature methodSignature=(MethodSignature)joinPoint.getSignature();

        String className=methodSignature.getDeclaringType().getSimpleName();

        String methodName=methodSignature.getName();

        String funName=methodSignature.getMethod().getAnnotation(BehaviorTrace.class).value();

        //统计时间

        long begin=System.currentTimeMillis();

        //插入原有的代码

        Object result=joinPoint.proceed();

        long duration=System.currentTimeMillis()-begin;

        Log.d("dcw",String.format("功能:%s,%s类的%s方法执行了,用时%d ms",funName,className,methodName,duration));



        return result;

    }

}

其中@Pointcut("execution(@com.dcw.aop_aspect.annotation.BehaviorTrace * *(..))")是定义切面规则,execution是切入点指示符,这里用法很多样灵活,具体可以自己百度。

@ Around代表在切入点joinPoint.proceed()前后都有代码运行,

@ Before是在所拦截方法执行之前执行一段逻辑

@ After是在所拦截方法执行之后执行一段逻辑

其中@ Before,@ After注解方法里面只需要写切入内容,不需要调用joinPoint.proceed(),如果在Before里面做如下操作是会报异常的。


@Before("methodAnnotatedWithBehaviorTrace()")

    public Object beforeJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable{

        //插入原有的代码

        Object result=joinPoint.proceed();

        Log.d("dcw","before操作");



        return result;

    }

注意同一个方法被多个Aspect类拦截可能会报出异常。

具体使用的时候只需要在外部定义一个方法就实现@BehaviorTrace注解就可以,你可以在Log区域打印出这个方法执行的时间。


    @BehaviorTrace(value = "摇一摇",value2="haha")

    public void mShake(View view){

        SystemClock.sleep(new Random().nextInt(100));

    }

这就实现了一个依赖于Aspect的切面实现方法耗时检测功能了。

上一篇下一篇

猜你喜欢

热点阅读