一、配置方式
1.1、注解
@Aspect 声明该类为一个切面
@Pointcut 切入点
@Before 前置通知
@After 后置通知,方法执行完之后
@AfterReturning 返回通知,成功执行之后
@AfterThrowing 异常通知,抛出异常之后
@Around 环绕通知
1.2、XML
二、切入点表达式(Pointcut Expression)
|——>指示符(designator)
表达式(Expression)——> |——>通配符(wildcard)
|——>运算符(operator)
2.1、表达式符号
2.1.1、指示符
匹配方法:
execution()
匹配注解:
@target()、@args()、@within()、@annotation()
匹配包/类型:
within()
匹配对象:
this()、bean()、target()
匹配参数:
args()
2.1.2、通配符
*:匹配任意数量的字符
+:匹配指定的类及其子类
..:匹配任意数量的子包或参数
2.1.3、运算符
&&、
||、
!,匹配其他过滤条件,不多说,同Java
2.2、示例
2.2.1、匹配包/类型
//匹配UserService下所有的方法
@Pointcut("within(org.ljy.service.UserService)")
public void test(){...}
//匹配org.ljy包下的所有类的方法
@Pointcut("within(org.ljy.*)")
public void test(){...}
//匹配org.ljy包及其子包下的所有类的方法
@Pointcut("within(org.ljy..*)")
public void test(){...}
2.2.2、匹配对象
//匹配AOP对象的目标对象为指定类型,在此为DemoDao,
this代表的是AOP代理对象
@Pointcut("this(org.ljy.DemoDao)")
public void test(){...}
//匹配实现了IDao接口的目标对象的方法,
target为原始对象,即非AOP代理对象
@Pointcut("target(org.ljy.IDao)")
public void test(){...}
//匹配所有以Service结尾的bean里的方法,
bean表示以bean的名字匹配
@Pointcut("bean(*Service)")
public void test(){...}
2.2.3、匹配参数
//匹配所有以find开头且只有一个参数类型为Long的方法
@Pointcut("execution(* *..find*(Long))")
public void test(){...}
//匹配所有只有一个参数且类型为Long的方法
@Pointcut("args(Long)")
public void test(){...}
//匹配所有以find开头且第一个参数类型为Long的方法
@Pointcut("execution(* *..find*(Long,..))")
public void test(){...}
//匹配所有第一个参数类型为Long的方法
@Pointcut("args(Long,..)")
public void test(){...}
2.2.4、匹配注解
//匹配方法上有MyAnno注解的方法
@Pointcut("@annotation(MyAnno)")
public void test(){...}
//匹配方法上有MyAnno注解的类里面的所有方法,要求MyAnno的RententionPolicy为CLASS级别
@Pointcut("@within(MyAnno)")
public void test(){...}
//匹配方法上有MyAnno注解的类里面的所有方法,要求MyAnno的RententionPolicy为RUNTIME级别
@Pointcut("@target(MyAnno)")
public void test(){...}
//匹配传入的参数的类上有MyAnno注解的方法
@Pointcut("@args(MyAnno)")
public void test(){...}
2.3、execution()表达式
2.3.1、格式
execution(modifer-pattern? returnType-pattern declaringType-pattern? name-pattern(param-pattern...) throws-pattern?)
翻译一下:
execution(修饰符? 返回类型 包名? 方法名(参数名...) 异常?)
【?表示可省略部分】
如:
//匹配修饰符为public,返回类型为User的org.ljy下以Service结尾的类下的所有方法
execution("public User org.ljy.*Service.*(..) ")
三、Spring AOP的实现原理
|——>代理模式
|——>设计模式——> |
| |——>责任链模式
实现原理——> |
| |——>JDK
|——>实现方式——> |
|——>cglib
3.1、代码的织入
3.1.1、织入时期
- 编译期(AspectJ)
- 类加载时(AspectJ 5+)
- 运行时(Spring AOP)
3.2、代理模式
3.2.1、静态代理
调用被代理的对象(Target)的目标方法的客户端(Caller)通过代理类(Proxy)间接与被代理的对象(Target)进行通讯。
客户端(Caller)通过接口调用目标方法,而代理类(Proxy)收到客户端发来的请求时会把真正的执行交给被代理的类(Target),而代理类可以在目标方法执行前后执行其他的方法。
3.2.2、动态代理
|——>基于接口的(JDK方式)
实现方式——> |
|——>基于继承的(cglib)
- JDK代理:代理类要实现InvocationHandler接口,且只能基于接口实现代理。
- Cglib代理:代理类实现MethodInteceptor接口,通过继承方式实现代理,所以无法代理private和final以及static方法。
3.3、Spring对代理模式的选择
- 如果目标对象实现了接口,则使用JDK代理
- 如果目标对象没有实现接口,则使用Cglib代理
- 如果目标对象实现了接口,但强制使用Cglib,则使用Cglib代理