本文内容
Spring 10种切点表达式详解
切点的组合使用
公共切点的定义
声明切点@Poincut
@Poincut 的使用格式如下:
@Poincut("PCD") // 切点表达式 表示对哪些方法进行增强
public void pc(){
} // 切点签名,返回值必须为void
10种切点表达式
AspectJ的切点指示符AspectJ pointcut designators (PCD) ,也就是俗称的切点表达式,Spring中支持10种,如下表:
简单介绍下AspectJ中常用的3个通配符:
*:匹配任何数量字符
..:匹配任何数量字符的重复,如任何数量子包,任何数量方法参数
+:匹配指定类型及其子类型,仅作为后缀防过载类型模式后面。
execution
用于匹配方法执行,最常用。
格式说明
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
其中带 ?号的 modifiers-pattern?,declaring-type-pattern?,throws-pattern?是可选项
ret-type-pattern,name-pattern, parameters-pattern是必选项
modifier-pattern? 修饰符匹配,如public 表示匹配公有方法,*表示任意修饰符
ret-type-pattern 返回值匹配,* 表示任何返回值,全路径的类名等
declaring-type-pattern? 类路径匹配
name-pattern 方法名匹配,* 代表所有,xx*代表以xx开头的所有方法
(param-pattern) 参数匹配,指定方法参数(声明的类型),(..)代表所有参数,(*,String)代表第一个参数为任何值,第二个为String类型,(..,String)代表最后一个参数是String类型
throws-pattern? 异常类型匹配
举例说明
public class PointcutExecution {
// com.crab.spring.aop.demo02包下任何类的任意方法
@Pointcut("execution(* com.crab.spring.aop.demo02.*.*(..))")
public void m1(){
}
// com.crab.spring.aop.demo02包及其子包下任何类的任意方法
@Pointcut("execution(* com.crab.spring.aop.demo02..*.*(..))")
public void m2(){
}
// com.crab.spring.aop包及其子包下IService接口的任意无参方法
@Pointcut("execution(* com.crab.spring.aop..IService.*(..))")
public void m3(){
}
// com.crab.spring.aop包及其子包下IService接口及其子类型的任意无参方法
@Pointcut("execution(* com.crab.spring.aop..IService+.*(..))")
public void m4(){
}
// com.crab.spring.aop.demo02.UserService类中有且只有一个String参数的方法
@Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(String))")
public void m5(){
}
// com.crab.spring.aop.demo02.UserService类中参数个数为2且最后一个参数类型是String的方法
@Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(*,String))")
public void m6(){
}
// com.crab.spring.aop.demo02.UserService类中最后一个参数类型是String的方法
@Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(..,String))")
public void m7(){
}
}
within
格式说明
within(类型表达式):目标对象target的类型是否和within中指定的类型匹配
匹配规则: target.getClass().equals(within表达式中指定的类型)
举例说明
public class PointcutWithin {
// 匹配 com.crab.spring.aop.demo02包及其子包下任何类的任何方法
@Pointcut("within(com.crab.spring.aop.demo02..*)")
public void m() {
}
// 匹配m.crab.spring.aop.demo02包及其子包下IService类型及其子类型的任何方法
@Pointcut("within(com.crab.spring.aop.demo02..IService+)")
public void m2() {
}
// 匹配com.crab.spring.aop.demo02.UserService类中所有方法,不含其子类
@Pointcut("within(com.crab.spring.aop.demo02.UserService)")
public void m3() {
}
}
this
格式说明
this(类型全限定名):通过aop创建的代理对象的类型是否和this中指定的类型匹配;this中使用的表达式必须是类型全限定名,不支持通配符。
this(x)的匹配规则是:x.getClass.isAssingableFrom(proxy.getClass)
举例说明
package com.crab.spring.aop.demo02.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;
/**
* @author zfd
* @version v1.0
* @date 2022/2/6 21:41
* @关于我 请关注公众号 螃蟹的Java笔记 获取更多技术系列
*/
@Aspect
public class PointcutThis {
interface I1{
void m();
}
static class C1 implements I1{
@Override
public void m() {
System.out.println("C1 m()");
}
}
// 匹配 I1类型或是其子类
@Pointcut("this(com.crab.spring.aop.demo02.aspectj.PointcutThis.I1)")
public void pc(){
}
@Before("pc()")
public void before(JoinPoint joinPoint) {
System.out.println("before: " + joinPoint);
}
public static void main(String[] args) {
C1 target = new C1();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
proxyFactory.setTarget(target);
// proxyFactory.setProxyTargetClass(true);
// 获取C1上所有接口 spring工具类提供的方法
Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);
// 设置代理接口
proxyFactory.setInterfaces(allInterfaces);
// 添加切面
proxyFactory.addAspect(PointcutThis.class);
// 获取代理
I1 proxy = proxyFactory.getProxy();
// 调用方法
proxy.m();
System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));
System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));
//判断代理对象是否是C1类型的
System.out.println(C1.class.isAssignableFrom(proxy.getClass()));
}
}
来观察下输出
before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutThis$C1.m())
C1 m()
JDK代理? false
CGLIB代理? true
true
使用JDK动态代理生成的代理对象,其类型是I1类型。
思考下:将切点表达式改成下面的输出结果是?
// 匹配 C1类型或是其子类
@Pointcut("this(com.crab.spring.aop.demo02.aspectj.PointcutThis.C1)")
public void pc(){}
target
格式说明
target(类型全限定名):判断目标对象的类型是否和指定的类型匹配;表达式必须是类型全限定名,不支持通配符。
target(x)匹配规则:x.getClass().isAssignableFrom(target.getClass());
举例说明
@Aspect
public class PointcutTarget {
interface I1{
void m();
}
static class C1 implements I1{
@Override
public void m() {
System.out.println("C1 m()");
}
}
// 匹配目标类型必须是
@Pointcut("target(com.crab.spring.aop.demo02.aspectj.PointcutTarget.C1)")
public void pc(){
}
@Before("pc()")
public void before(JoinPoint joinPoint) {
System.out.println("before: " + joinPoint);
}
public static void main(String[] args) {
C1 target = new C1();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
proxyFactory.setTarget