Spring AOP基础

AOP基本术语

Advice-通知

Before

前置通知,目标方法被调用前调用

After

后置通知,目标方法完成后调用通知,并不关心方法的输出是什么

After-returning

目标方法成功执行后调用

After-throwing

目标方法抛出异常后调用

Around

通知包裹了被通知的方法,在被通知的方法调用前和调用后执行自定义行为

Pointcut-切点

定义哪些方法是需要被通知的

Aspect-切面

Advice+Pointcut=Aspect

Join Point-连接点

应用执行过程中能够插入切面的时间点
如:抛出异常时、调用方法时......

Introduction-引入

向现有类添加新的方法或属性

Weaving-织入

把切面应用到目标对象并创建新的代理对象

切点详解

Spring的AOP中,使用AspectJ切点表达式来定义切点
Spring仅支持AspectJ切点指示器的一个子集

arg()

指定方法的参数类型

@args()

指定方法的参数由指定注解标注

execution()

指定方法,方法由切点表达式描述 (* 包名.类名.方法名(参数))

  • 表示返回任意类型
    参数如果是 .. ,表示任意参数

within()

指定方法类型

@within()

指定方法的注解类型

@annotation()

指定方法带有指定注解

其他

bean()

bean("beanId")-在指定bean中生效
!bean("beanId")-在指定bean中不生效

切点之间可以使用 &&、||、!连接,如果在xml中描述,使用 and、or、not

定义切面

package com.zln.aop;
import org.aspectj.lang.annotation.*;
/**
 * 定义切面
 * Created by sherry on 17/3/9.
 */
@Aspect
public class Audience {
    /**
     * 切点
     */
    @Pointcut("execution(* com.zln.aop.Performance.*(..))")
    public void performance(){}
    /**
     * 前置通知
     */
    @Before("performance()")
    public void silenceCellPhones(){
        System.out.println("前置通知:表演前手机静音");
    }
    @Before("performance()")
    public void takeSeats(){
        System.out.println("前置通知:就坐");
    }
    @AfterReturning("performance()")
    public void applause(){
        System.out.println("返回通知:表演结束,鼓掌");
    }
    @AfterThrowing("performance()")
    public void demandRefund(){
        System.out.println("异常通知:表演失败");
    }
}
package com;
import com.zln.aop.Audience;
import org.springframework.context.annotation.*;
/**
 * Created by sherry on 17/3/9.
 */
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppBeans {
    @Bean
    public Audience audience(){
        return new Audience();
    }
}

运行测试

package com.zln.aop;
import org.springframework.stereotype.Component;
/**
 * Created by sherry on 17/3/9.
 */
@Component
public class Performance{
    public void perform() {
        System.out.println("正在表演");
    }
}

环绕通知

package com.zln.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
 * 定义切面
 * Created by sherry on 17/3/9.
 */
@Aspect
public class Audience {
    /**
     * 切点
     */
    @Pointcut("execution(* com.zln.aop.Performance.*(..))")
    public void performance(){}
    /**
     * 前置通知
     */
    @Before("performance()")
    public void silenceCellPhones(){
        System.out.println("前置通知:表演前手机静音");
    }
    @Before("performance()")
    public void takeSeats(){
        System.out.println("前置通知:就坐");
    }
    @AfterReturning("performance()")
    public void applause(){
        System.out.println("返回通知:表演结束,鼓掌");
    }
    @AfterThrowing("performance()")
    public void demandRefund(){
        System.out.println("异常通知:表演失败");
    }
    @Around("performance()")
    public void watch(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("环绕通知1");
        try {
            proceedingJoinPoint.proceed();
            System.out.println("环绕通知2");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

环绕通知的proceedingJoinPoint.proceed();比较神奇,如果没有这句,相当于代码阻塞,如果调用多次,相当于执行多次目标方法

通知的方法参数

package com.zln.aop;
import org.springframework.stereotype.Component;
/**
 * Created by sherry on 17/3/9.
 */
@Component
public class Performance{
    public void perform(int i) {
        System.out.println("正在表演");
    }
}
    //如果不是int等基本类型,要使用类的全限定名
    @Pointcut("execution(* com.zln.aop.Performance.*(int))")
    public void performance(){}
    /**
     * 前置通知
     */
    @Before("performance()&&args(i)")
    public void silenceCellPhones(int i){
        System.out.println("前置通知:表演前手机静音"+i);
    }

调用perform方法的时候,参数i的值就会被获取到

原文地址:https://www.cnblogs.com/sherrykid/p/7058008.html