Pointcut 表达式

简介: 1. AOP 概念篇今天介绍 Pointcut 的表达式

网络异常,图片无法展示
|

  1. AOP 概念篇

今天介绍 Pointcut 的表达式


通配符


常见的通配符如下


..

含义一:方法表达式中、代表任意数量的参数

@Service
public class HelloService {
    public void sayHi(String name) {
        System.out.println("hi," + name);
    }
    public void sayHi(String firstName, String lastName) {
        System.out.println("hi," + firstName + lastName);
    }
}
@Pointcut("execution(public void com.example.junitspringboot.service.HelloService.sayHi(..))")
 public void pointcut(){}
复制代码


那么上面的 Pointcut 表达式就能将 HelloService 中的两个连接点都包括进去。

  • 连接点:程序执行的某个特定位置,比如某个方法调用前、调用后,方法抛出异常后,对类成员的访问以及异常处理程序块的执行等。一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。它自身还可以嵌套其他的 Joinpoint。AOP 中的 Joinpoint 可以有多种类型:构造方法调用,字段的设置和获取,方法的调用,方法的执行,异常的处理执行,类的初始化。Spring 仅支持方法执行类型的 Joinpoint。


含义二:类定义表达式中、代表任意子包

@Component
@Aspect
public class ServiceAop {
    @Pointcut("execution(public void com.example.junitspringboot..HelloService.sayHi(..))")
    public void pointcut(){}
    @Around("pointcut()")
    public Object before(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("before");
        return proceedingJoinPoint.proceed();
    }
}
// 注意包名
package com.example.junitspringboot.service.inner;
import org.springframework.stereotype.Service;
@Service("innerHelloService")
public class HelloService {
    public void sayHi(String firstName, String lastName) {
        System.out.println("hi," + firstName + lastName);
    }
}
// 注意包名
package com.example.junitspringboot.service;
public class HelloService {
    public void sayHi(String name) {
        System.out.println("hi," + name);
    }
}
复制代码


+

匹配给定类及其子类

public interface Person {
    void say();
}
@Service
public class Man implements Person{
    @Override
    public void say() {
        System.out.println("man");
    }
}
@Service
public class Woman implements Person {
    @Override
    public void say() {
        System.out.println("woman");
    }
}
@Pointcut("within(com.example.junitspringboot.service.Person+)")
public void pointcut(){}
复制代码

那么接口 Person 的子类所有实现的方法都会被增强。


*

匹配任意数量的字符

// com.example.junitspringboot.service 包所有的类的所有方法
@Pointcut("within(com.example.junitspringboot.service.*)")
public void pointcut1(){}
// 所有以 say 开头的方法
@Pointcut("execution(* say*(..))")
public void pointcut2(){}
复制代码


execution


使用得最多的表达式、用于指定方法的执行。? 表示非必填

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? 
  name-pattern(param-pattern) throws-pattern?)
复制代码
  • modifiers-pattern?  表示修饰符、如 public、protected
  • ret-type-pattern 返回类型、必填。 如果使用通配符 * 代表任意的返回类型
  • declaring-type-pattern? 表示声明方法的类。
  • name-pattern 表示方法名。
  • param-pattern 表示方法参数、如果使用通配符 .. 则代表任意参数
  • throws-pattern? 表示方法抛出的异常


例子

execution(public * com.example..say*(..))  
复制代码
  • 修饰符为 public
  • 任意返回类型
  • 在 com.example 包或者其子包下
  • 方法名称以 say 开头
  • 任意参数
@Pointcut("execution( * say*(..))")
复制代码
  • 任意返回类型
  • 方法名称以 say 开头
  • 任意参数
@Pointcut("execution(* *(..) throws Exception)")
复制代码
  • 方法声明抛出 Exception 的任意方法


within

指定特定类型、类型中所有的方法都被拦截。

@Pointcut("within(com.example.junitspringboot.service.Person)")
复制代码
  • Person 类所有外部的方法调用都被拦截
@Pointcut("within(com.example.junitspringboot.service.Person+)")
复制代码
  • Person 类及其子类所有外部的方法调用都被拦截
@Pointcut("within(com.example.junitspringboot.service..*)"
复制代码
  • 所有在 com.example.junitspringboot.service 包以及子包下的所有类的所有外部调用方法


this

this通过判断代理类是否按类型匹配指定类来决定是否和切点匹配。 用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配。 this中使用的表达式必须是类型全限定名,不支持通配符。

public class ServiceAop implements Ordered {
    @Pointcut("this(com.example.junitspringboot.service.ISwimming)")
    public void thisPointcut(){}
    @Before("thisPointcut()")
    public void before(JoinPoint joinPoint) {
        System.out.println("before");
    }
    @Override
    public int getOrder() {
        return 1;
    }
}
// 使用引介使 Man 也实现 ISwimming 接口
@Component
@Aspect
public class IntroductionAop implements Ordered {
    @DeclareParents(value = "com.example.junitspringboot.service.Man", defaultImpl = Swimming.class)
    public ISwimming swimming;
    @Override
    public int getOrder() {
        return 0;
    }
}
// 微信公众号:CoderLi
public interface ISwimming {
    void swim();
}
// 微信公众号:CoderLi
@Service
public class Man implements Person{
    @Override
    public void say() {
        System.out.println("man");
    }
}
 ConfigurableApplicationContext context = SpringApplication.run(JunitSpringBootApplication.class, args);
 context.getBean(Man.class).say();
 ((ISwimming) context.getBean(Man.class)).swim();
复制代码

当我们调用 swim 方法的时候、会被拦截增强。当我们调用 say 方法的时候、同样也会被拦截增强,这个就是 this 会将代理类实现的其他接口的方法也会被拦截增强


target

target 通过判断目标类是否按类型匹配指定类来决定连接点是否匹配. 用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;

@Pointcut("target(com.example.junitspringboot.service.ISwimming)")
复制代码

同样也是上面的例子。修改切点表达式为 target 、say 方法不再被拦截增强。


args

用来匹配参数

@Pointcut("args(..)")
复制代码
  • 匹配任意参数的方法
@Pointcut("args()")
复制代码
  • 匹配任何不带参数的方法


@target

匹配当被代理的目标对象对应的类型及其父类型上拥有指定的注解时

@Pointcut("@target(com.example.junitspringboot.anno.AopFlag) && within(com.example.junitspringboot..*)")
复制代码
  • 匹配在包 com.example.junitspringboot..* 下所有被 AopFlag 修饰的类的所有方法


@args

@args匹配被调用的方法上含有参数,且对应的参数类型上拥有指定的注解的情况。

@Pointcut("@args(com.example.junitspringboot.anno.AopFlag)")
// 微信公众号:CoderLi
@AopFlag
public class Data {
}
public interface Person {
    void say(Data data);
}
复制代码


@within

@within用于匹配被代理的目标对象对应的类型或其父类型拥有指定的注解的情况,但只有在调用拥有指定注解的类上的方法时才匹配。

@Pointcut("@within(com.example.junitspringboot.anno.AopFlag) && within(com.example.junitspringboot..*)")
复制代码

这个功能上貌似跟 @target 有点像了


@annotation

也是比较常用的一个注解、用于匹配方法上拥有指定注解的情况。

@Pointcut("@annotation(com.example.junitspringboot.anno.AopFlag) && within(com.example.junitspringboot..*)")
复制代码


bean

Spring 特有的一个表达式。

@Pointcut("bean(man)")
复制代码

拦截该 bean 的所有方法

10 种切点的表达式介绍完毕



目录
相关文章
|
SQL Oracle 关系型数据库
Oracle之如何组合去重
Oracle之如何组合去重
514 1
|
存储 SQL 关系型数据库
【MySQL 数据库】9、存储过程
【MySQL 数据库】9、存储过程
1171 0
|
10月前
|
开发工具 git C++
【够用就好002】外行第一次发布github项目仓库
#deepseek#自学 记录外行学习代码的历程 今天是上传自己的工具代码到github仓库,一直以来是伸手党克隆别人的项目,今天在deepseek的辅导下上传自己的内容。
|
数据库
Unknown column ‘字段名‘ in ‘field list‘解决方法
Unknown column ‘字段名’ in 'field list’英语翻译过来就是未知列的字段名在字段表中,也就是说数据库表中的字段名在实体类中找不到。 解决方案如下: 查看实体类的属性名和数据库表中的名字是否一致(注意数据库表字段中是否有空格或者下划线)
4974 0
|
SQL 缓存 监控
14个Flink SQL性能优化实践分享
【7月更文挑战第12天】 1. **合理设置并行度**: 根据数据量和资源调整以提高处理速度. 2. **优化数据源**: 使用分区表并进行预处理减少输入量. 3. **数据缓存**: 采用 `BROADCAST` 或 `REPARTITION` 缓存常用数据. 4. **索引和分区**: 创建索引并按常用字段分区. 5. **避免不必要的计算**: 检查并移除多余的计算步骤. 6. **调整内存配置**: 分配足够内存避免性能下降. 7. **优化连接操作**: 选择适合大表和小表的连接方式. 8. **数据类型优化**: 选择合适类型以节省资源. ........
397 1
|
SQL 网络协议 关系型数据库
mysql 连接超时wait_timeout问题解决
com.mysql.jdbc.CommunicationsException: The last packet successfully received from the server was58129 seconds ago.The last packet sent successfully to the server was 58129 seconds ago, which is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or tes
|
Java
java操作内存,简单讲解varhandle的使用
本文介绍了Java中VarHandle的使用,它是一种从JDK 9开始引入的用于高效访问对象字段的特性。文章通过示例代码展示了如何通过VarHandle操作对象的字段,包括设置和获取字段值,以及如何通过MethodHandles.lookup().findVarHandle()方法获取VarHandle实例。VarHandle提供了一种比反射更高效的内存操作方式,并且支持原子操作。
309 0
java操作内存,简单讲解varhandle的使用
|
JSON Java 数据格式
实现自定义序列化和反序列化控制的5种方式
实现自定义序列化和反序列化控制的5种方式
element UI 中多行消息提示的实现(this.$message的换行)
element UI 中多行消息提示的实现(this.$message的换行)
820 0
|
SQL 存储 关系型数据库
AI代码提示工具可用于教学功能示例——MySQL
AI代码提示工具可用于教学功能示例——MySQL
300 0