【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)(下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)(下)

ComposablePointcut 组合切入点


从上面的例子中,每次我们只能定义一个切入点(切点表达式)。有的时候,一个切点可能难以描述目标连接点的信息,而是需要同时满足两个切入点才行,那么ComposablePointcut就派上了用场(aspectJ里面的&& ||等其实也能达到类似的效果)。


但是更好的方式是使用Spring提供的ComposalbePointcut把两个切点组合起来,通过切点的复合运行算表示,ComposalbePointcut可以将多个切点以并集或者交集的方式组合起来,提供切点之间复合运算的功能。


先看一个Demo:

public class Main {
    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory(new Person());
        // 声明一个通知(此处使用环绕通知 MethodInterceptor )
        Advice advice = (MethodInterceptor) invocation -> {
            System.out.println("============>放行前拦截...");
            Object obj = invocation.proceed();
            System.out.println("============>放行后拦截...");
            return obj;
        };
        // 先创建一个流程切入点
        ControlFlowPointcut controlFlowPointcut = new ControlFlowPointcut(Main.class, "funabc");
        // 再创建一个方法名切入点
        NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
        nameMatchMethodPointcut.addMethodName("say");
        // 创建一个复合切点 把上面两者并且进来
        ComposablePointcut cut = new ComposablePointcut();
        cut.intersection((Pointcut) controlFlowPointcut).intersection((Pointcut)nameMatchMethodPointcut);
        // 切点+通知(注意:此处放的是复合切面)
        Advisor advisor = new DefaultPointcutAdvisor(cut, advice);
        factory.addAdvisor(advisor);
        Person p = (Person) factory.getProxy();
        // 执行方法
        p.run();
        p.run(10);
        p.say();
        p.sayHi("Jack");
        p.say("Tom", 666);
        funabc(p);
    }
    private static void funabc(Person person) {
        person.run();
        person.say();
    }
}
输出:
我在run...
我在run...<10>
我在say...
Hi,Jack,你好
Tom----666
我在run...
============>放行前拦截...
我在say...
============>放行后拦截...


从结果中和上面对比我们能看出,两个切入点有并且的效果。(只有say方法被拦截了,run方法并没有被拦截)


ComposablePointcut 源码分析


public class ComposablePointcut implements Pointcut, Serializable {
  // 它持有ClassFilter 和 MethodMatcher ,最终通过它去组合匹配
  private ClassFilter classFilter;
  private MethodMatcher methodMatcher;
  // 构造函数一个共5个
  // 匹配所有类所有方法的复合切点
  public ComposablePointcut() {
    this.classFilter = ClassFilter.TRUE;
    this.methodMatcher = MethodMatcher.TRUE;
  }
  // 匹配特定切点的复合切点(相当于把这个节点包装了一下而已)
  public ComposablePointcut(Pointcut pointcut) {
    Assert.notNull(pointcut, "Pointcut must not be null");
    this.classFilter = pointcut.getClassFilter();
    this.methodMatcher = pointcut.getMethodMatcher();
  }
  // 匹配特定类**所有方法**的复合切点
  public ComposablePointcut(ClassFilter classFilter) {
    Assert.notNull(classFilter, "ClassFilter must not be null");
    this.classFilter = classFilter;
    this.methodMatcher = MethodMatcher.TRUE;
  }
  // 匹配**所有类**特定方法的复合切点
  public ComposablePointcut(MethodMatcher methodMatcher) {
    Assert.notNull(methodMatcher, "MethodMatcher must not be null");
    this.classFilter = ClassFilter.TRUE;
    this.methodMatcher = methodMatcher;
  }
  // 匹配特定类特定方法的复合切点(这个是最为强大的)
  public ComposablePointcut(ClassFilter classFilter, MethodMatcher methodMatcher) {
    Assert.notNull(classFilter, "ClassFilter must not be null");
    Assert.notNull(methodMatcher, "MethodMatcher must not be null");
    this.classFilter = classFilter;
    this.methodMatcher = methodMatcher;
  }
  // 匹配特定类特定方法的复合切点(这个是最为强大的)
  public ComposablePointcut union(ClassFilter other) {
    this.classFilter = ClassFilters.union(this.classFilter, other);
    return this;
  }
  // ==========3个并集(union) / 3个交集(intersection) 运算的方法========
  public ComposablePointcut intersection(ClassFilter other) {
    this.classFilter = ClassFilters.intersection(this.classFilter, other);
    return this;
  }
  public ComposablePointcut union(MethodMatcher other) {
    this.methodMatcher = MethodMatchers.union(this.methodMatcher, other);
    return this;
  }
  public ComposablePointcut intersection(MethodMatcher other) {
    this.methodMatcher = MethodMatchers.intersection(this.methodMatcher, other);
    return this;
  }
  public ComposablePointcut union(Pointcut other) {
    this.methodMatcher = MethodMatchers.union(
        this.methodMatcher, this.classFilter, other.getMethodMatcher(), other.getClassFilter());
    this.classFilter = ClassFilters.union(this.classFilter, other.getClassFilter());
    return this;
  }
  public ComposablePointcut intersection(Pointcut other) {
    this.classFilter = ClassFilters.intersection(this.classFilter, other.getClassFilter());
    this.methodMatcher = MethodMatchers.intersection(this.methodMatcher, other.getMethodMatcher());
    return this;
  }
  ...
}


ComposablePointcut没有提供直接对两个切点类型并集交集的运算的方法。若需要,请参照org.springframework.aop.support.Pointcuts这个工具类里面有对两个Pointcut进行并集、交集的操作(后面再介绍)


AnnotationMatchingPointcut 注解切入点


根据对象是否有指定类型的注解来匹配Pointcut

有两种注解,类级别注解和方法级别注解。

//仅指定类级别的注解, 标注了 ClassLevelAnnotation 注解的类中的**所有方法**执行的时候,将全部匹配。  
AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(ClassLevelAnnotation.class);  
// === 还可以使用静态方法创建 pointcut 实例  
AnnotationMatchingPointcut pointcut = AnnotationMatchingPointcut.forClassAnnotation(ClassLevelAnnotation.class);  
//仅指定方法级别的注解,标注了 MethodLeavelAnnotaion 注解的**方法(忽略类匹配)都将匹配**  
AnnotationMatchingPointcut pointcut = AnnotationMatchingPointcut.forMethodAnnotation(MethodLevelAnnotation.class);  
==========这个是同时想限定:===============
//同时限定类级别和方法级别的注解,只有标注了 ClassLevelAnnotation 的类中 ***同时***标注了 MethodLevelAnnotation 的方法才会匹配  
AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(ClassLevelAnnotation.class, MethodLevelAnnotation.class);  


Demo:略


总结


其实,这些基础的知识也是为了去更好的理解Spring的自动代理创建器铺路

相关文章
|
16天前
|
存储 缓存 算法
HashMap深度解析:从原理到实战
HashMap,作为Java集合框架中的一个核心组件,以其高效的键值对存储和检索机制,在软件开发中扮演着举足轻重的角色。作为一名资深的AI工程师,深入理解HashMap的原理、历史、业务场景以及实战应用,对于提升数据处理和算法实现的效率至关重要。本文将通过手绘结构图、流程图,结合Java代码示例,全方位解析HashMap,帮助读者从理论到实践全面掌握这一关键技术。
57 13
|
17天前
|
数据可视化 数据挖掘 BI
团队管理者必读:高效看板类协同软件的功能解析
在现代职场中,团队协作的效率直接影响项目成败。看板类协同软件通过可视化界面,帮助团队清晰规划任务、追踪进度,提高协作效率。本文介绍看板类软件的优势,并推荐五款优质工具:板栗看板、Trello、Monday.com、ClickUp 和 Asana,助力团队实现高效管理。
44 2
|
2月前
|
运维 持续交付 云计算
深入解析云计算中的微服务架构:原理、优势与实践
深入解析云计算中的微服务架构:原理、优势与实践
70 1
|
9天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
2天前
|
存储 物联网 大数据
探索阿里云 Flink 物化表:原理、优势与应用场景全解析
阿里云Flink的物化表是流批一体化平台中的关键特性,支持低延迟实时更新、灵活查询性能、无缝流批处理和高容错性。它广泛应用于电商、物联网和金融等领域,助力企业高效处理实时数据,提升业务决策能力。实践案例表明,物化表显著提高了交易欺诈损失率的控制和信贷审批效率,推动企业在数字化转型中取得竞争优势。
27 14
|
10天前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
55 1
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
131 2
|
2月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
57 2
|
2月前
|
前端开发 Java 开发者
Spring MVC中的控制器:@Controller注解全解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序控制层的核心。它不仅简化了控制器的定义,还提供了灵活的请求映射和处理机制。本文将深入探讨`@Controller`注解的用法、特点以及在实际开发中的应用。
94 0
|
8月前
|
安全 Java Spring
Spring之Aop的底层原理
Spring之Aop的底层原理

推荐镜像

更多