Android aop Advice(通知、增强)

作者: 唠嗑008 | 来源:发表于2019-11-29 12:24 被阅读0次

推荐阅读系列文章

Android aop切点表达式(execution)
Android aop(AspectJ)查看新的代理类
Android AOP面向切面编程详解
防止按钮连续点击

AOP AspectJ方案有三要素:

  • @Aspect:定义切面类;
  • @Pointcut:定义切点;
  • Advice(通知/增强):定义一个通知方法,是处理逻辑的。

Advice(通知/增强)方法的作用是:在切点方法执行前、后,甚至是抛出异常的时候去做一些其它逻辑操作。

具体来说分为5种通知:

  • @Before(): 切点方法执行之前执行
  • @After(): 切点方法执行之后执行
  • @Around(): 在切点方法执行前、后都可以做一些操作
  • @AfterReturning():切点方法返回结果之后执行
  • @AfterThrowing():异常通知,切点抛出异常时执行

@Before()

在目标方法执行之前做一些操作,比如说在Activity生命周期方法打印日志。

MainActivity中定义过方法

    /**
     * 测试5种通知/增强
     */
    private void testAdvice(){
        Log.e(TAG, "MainActivity testAdvice(): " );
    }

在切面类中定义如下方法

    @Before("execution(* com.zx.aop1.MainActivity.testAdvice(..))")
    public void testBefore(){
        Log.e(TAG, "testBefore: before testAdvice() method " );
    }

@Before执行结果

@Before.png

@After()

在目标方法执行之后做一些操作,比如说释放资源等。

    @After("execution(* com.zx.aop1.MainActivity.testAdvice(..))")
    public void testAfter(){
        Log.e(TAG, "testAfter: after testAdvice() method " );
    }

@After执行结果

@After.png

@Around()

这种应用场景很多,比如说在做xx操作之前检查权限;还有登录检查;防止按钮重复点击等。

@Around("execution(* com.zx.aop1.MainActivity.testAdvice(..))")
    public void testAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //在方法执行之前做一些事情
        Log.e(TAG, "testAfter: before testAdvice() method do something" );
        //调用原方法
        proceedingJoinPoint.proceed();
        //在方法执行之后做一些事情
        Log.e(TAG, "testAfter: after testAdvice() method do something" );
    }

这里有点区别,因为是环绕方法,需要手动调用原来的方法,具体来说是proceedingJoinPoint.proceed();``ProceedingJoinPointJoinPoint的子类,这里先不展开讲,后面再详细讲这2个类的作用。

@Around执行结果

Around.png

@AfterReturning()

这和@After类似,都是目标方法执行之后再做些其它操作;区别是
@AfterReturning()可以拿到原方法的返回结果。

 @AfterReturning(value = "execution(* com.zx.aop1.MainActivity.testAdvice(..))",returning = "result")
    public void testAfterReturning(String result){
        Log.e(TAG, "testBefore: AfterReturning testAdvice() method return: "+result );
    }

    /**
     * 测试5种通知/增强
     */
    private String testAdvice(){
        Log.e(TAG, "MainActivity testAdvice() perform: " );
        return "this is testAdvice() result";
    }

这里多了一个returning参数,注意,它的值必须和方法参数的名称一致,@AfterReturning标注的方法参数的类型必须和原方法返回类型一致。

@AfterReturning执行结果

@AfterReturning.png

下面对@AfterReturning()参数做一个详细解释:
源码定义

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterReturning {

    /**
     * The pointcut expression where to bind the advice
     */
    String value() default "";

    /**
     * The pointcut expression where to bind the advice, overrides "value" when specified
     */
    String pointcut() default "";

    /**
     * The name of the argument in the advice signature to bind the returned value to
     */
    String returning() default "";
    
    /**
     * When compiling without debug info, or when interpreting pointcuts at runtime,
     * the names of any arguments used in the advice declaration are not available.
     * Under these circumstances only, it is necessary to provide the arg names in 
     * the annotation - these MUST duplicate the names used in the annotated method.
     * Format is a simple comma-separated list.
     */
    String argNames() default "";

}

源码中定义了4个方法:
其中value()pointcut()功能基本一样:都是定义advice(通知/增强)方法中用到的切点表达式的。一样既可以是已有的切入点,也可直接定义切入点表达式。当指定了pointcut属性值后,value属性值将会被覆盖。通常用其中一个就行了。

returning()可以拿到目标方法的返回值。注意:它的值必须与Advice方法中定义的参数一致。returning()的值是String类型,别误以为返回参数只能是String,返回参数可以是任意类型,这里的值只是参数的名称而已。

@AfterThrowing()

切点抛出异常时执行这个通知方法

    @AfterThrowing(value = "execution(* com.zx.aop1.MainActivity.testException(..))", throwing = "exception")
    public void testAfterThrowing(Exception exception) {
        Log.e(TAG, "testBefore: AfterThrowing testException() method return: " + exception.toString());
//        throw exception;
    }

    /**
     * 测试异常
     */
    private void testException() {
        TextView textView = null;
        textView.setText("hello");
        Log.e(TAG, "MainActivity testException() perform: ");
    }

testException ()方法里面会抛出一个空指针异常,然后在testAfterThrowing()会执行。它与try catch的方式是不太一样的,try catch可以完全处理异常,但是@AfterThrowing却做不到,它只能在异常抛出之后做一些其它的逻辑处理,但是处理后异常仍然会往上一级调用者传播

另外需要注意:如果目标方法中出现异常,并由catch捕捉处理且catch又没有抛出新的异常,那么针对该目标方法的AfterThrowing增强处理将不会被执行。

结论:我目前的感觉是这个通知注解没什么用。先做个了解,后面再看看。

JoinPoint和ProceedingJoinPoint

JoinPoint

JoinPoint其实就是封装了切点方法相关的信息,

    @Before("execution1()")
    public void testExecution(JoinPoint joinPoint){
        Log.e(TAG, "testExecution ----: "+joinPoint.toString() );
    }

JoinPoint方法详解

public interface JoinPoint {  
   String toString();         //连接点相关信息  
   Object getThis();         //返回AOP代理对象  
   Object getTarget();       //返回目标对象  
   Object[] getArgs();       //返回切点方法参数列表  
   Signature getSignature();  //返回当前连接点签名  
   SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置  
   String getKind();        //连接点类型  
   StaticPart getStaticPart(); //返回连接点静态部分  
  }  
ProceedingJoinPoint

ProceedingJoinPointJoinPoint的子接口,该对象只用在@Around的切面方法中

@Around("execution(* *..MainActivity.testAOP())")
    public void onActivityMethodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        String key = proceedingJoinPoint.getSignature().toString();
        Log.e(TAG, "onActivityMethodAroundFirst: before " + key + "do something");
        //执行原方法
        proceedingJoinPoint.proceed();
        Log.e(TAG, "onActivityMethodAroundSecond: after " + key + "do something");
    }

关键点在于proceed()方法,有没有发现,这个流程不就是代理模式吗?

方法详解

/**
 * ProceedingJoinPoint exposes the proceed(..) method in order to support around advice in @AJ aspects
 *
 * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
 */
public interface ProceedingJoinPoint extends JoinPoint {

    /**
     * 执行目标方法 
     *
     * @return
     * @throws Throwable
     */
    public Object proceed() throws Throwable;

    /**
     * 传入的新的参数去执行目标方法 
     *
     * @param args
     * @return
     * @throws Throwable
     */
    public Object proceed(Object[] args) throws Throwable;

}

写文不易,如果本文对你有所帮助,请点个关注

相关文章

  • Android aop Advice(通知、增强)

    推荐阅读系列文章 Android aop切点表达式(execution)Android aop(AspectJ)查...

  • Spring AOP 代理

    Spring AOP 代理 1. Spring AOP 增强类型 AOP 联盟为通知 Advice 定义了 org...

  • Spring接口代理实现

    AOP联盟通知类型AOP联盟为通知Advice定义了org.aopalliance.aop.Advice 开发通知...

  • Spring APO

    图片发自简书App AOP核心概念 Aspect(切面) Join Point(连接点) Advice(通知/增强...

  • Spring与设计模式

    适配器模式 在Spring的Aop中,使用的Advice(通知)来增强被代理类的功能。每个类型Advice都有对应...

  • AOP的基本术语

    通知、增强(Advice) 通知就是你想要的功能,在特定的连接点,AOP框架执行的动作。Spring切面可以应用5...

  • 03 AOP学习之五种通知

    Spring AOP五种通知详解 spring aop通知(advice)分成五类: 前置通知Before adv...

  • 笔试题 计算机

    spring aop通知(advice)分成五类:前置通知[Before advice]:在连接点前面执行,前置通...

  • Spring AOP

    Spring AOP 一、面向切面编程 1. AOP术语 1.1 ADVICE(增强) Spring提供了以下几种...

  • Spring AOP增强(Advice)

    Sring AOP通过PointCut来指定在那些类的那些方法上织入横切逻辑,通过Advice来指定在切点上具体做...

网友评论

    本文标题:Android aop Advice(通知、增强)

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