【小家Spring】Spring AOP各个组件概述与总结【Pointcut、Advice、Advisor、Advised、TargetSource、AdvisorChainFactory...】(上)

简介: 【小家Spring】Spring AOP各个组件概述与总结【Pointcut、Advice、Advisor、Advised、TargetSource、AdvisorChainFactory...】(上)

前言


Spring AOP作为整个Spring体系最最重要的分支之一,若干技术都是基于它的(比如事务、异步、缓存等)


前面通过好几篇文章,已经把Spring AOP内部的的运行流程等基本都叙述了一遍,但是通过小伙伴们反馈,还是晕头转向的:类太多了,且很多概念感觉很模糊,不知道咋用的。


因此本文就站在一个更高的角度,对Spring AOP部分用到的一些组件,进行概念上的、宏观上的进行一个概述和分析总结。

Spring AOP概述


AOP(Aspect-Oriented Programming)面向切面编程,它是在OOP的基础上诞生的一种编程模型。我们可以通熟易懂的理解为:在程序中具有公共特性的某些类/某些方法上进行拦截, 在方法执行的前面/后面/执行结果返回后 增加执行一些方法。


在Spring中,实现的底层原理是通过动态代理 / CGLIB来做的


Spring AOP组件总结


1、Pointcut


这个类位于 org.springframework.aop 包中,它的作用就是定义切面的匹配点。(简单的说就是我去切哪些类、哪些方法…) 在 Spring Aop 中匹配的点主要是 class 与 method 这两个方面, 分别为ClassFilter 与 MethodFilter

// 由 ClassFilter 与 MethodMatcher 组成的 pointcut
public interface Pointcut {
    // 类过滤器, 可以知道哪些类需要拦截
    ClassFilter getClassFilter();
    // 方法匹配器, 可以知道哪些方法需要拦截
    MethodMatcher getMethodMatcher();
    // 匹配所有对象的 Pointcut
    Pointcut TRUE = TruePointcut.INSTANCE;
}


在 Spring 中主要有以下几个类,介绍如下:


  1. NameMatchMethodPointcut:通过刚发名进行精确匹配的。 (PS: 其中 ClassFilter = ClassFilter.TRUE)
  2. ControlFlowPointcut:根据在当前线程的堆栈信息中的方法名来决定是否切入某个方法(效率较低)
  3. ComposablePointcut:组合模式的 Pointcut, 主要分成两种: 1.组合中所有都匹配算成功 2. 组合中都不匹配才算成功
  4. JdkRegexpMethodPointcut:通过 正则表达式来匹配方法(PS: ClassFilter.TRUE)
  5. AspectJExpressionPointcut:通过 AspectJ 包中的组件进行方法的匹配(切点表达式)
  6. TransactionAttributeSourcePointcut:通过 TransactionAttributeSource 在 类的方法上提取事务注解的属性 @Transactional 来判断是否匹配, 提取到则说明匹配, 提取不到则说明匹配不成功
  7. AnnotationJCacheOperationSource:支持JSR107的cache相关注解的支持


上述中的 TransactionAttributeSourcePointcut 其实就是Spring注解式事务的 Pointcut。通过匹配方法上 @Transactional 标签来确定方法是否匹配;(事务篇会分析它的源码)


2、Advice

Advice: 建议忠告, 劝告, 通知。它其实最开始是 aopalliance 包中的一个空接口, 接口的存在主要是为了标示对应类为 Advice;


在Spring Aop 中 Advice 其实表示的是在 Pointcut 点上应该执行的方法。而这些方法可以在目标方法之前、之后、包裹、抛出异常等等任何地方执行。


Advice: 其主要分成两类:普通advice 与Interceptor/MethodInterceptor:


普通Advice :

  1. MethodBeforeAdvice:在目标方法之前执行,主要实现有:

1. AspectJMethodBeoreAdvice:这是通过解析被 org.aspectj.lang.annotation.Before 注解注释的方法时解析成的Advice


  2.AfterReturningAdvice:在切面方法执行后(这里的执行后指不向外抛异常, 否则的话就应该是 AspectJAfterThrowingAdvice 这种 Advice) 主要实现有:

1. AspectJAfterAdvice:解析 AspectJ 中的 @After 注解来生成的 Advice(PS: 在java中的实现其实就是在 finally 方法中调用以下对应要执行的方法)

2. AspectJAfterReturningAdvice:解析 AspectJ 中的@AfterReturning 属性来生成的 Advice(PS: 若切面方法抛出异常, 则这里的方法就将不执行)

3. AspectJAfterThrowingAdvice:解析 AspectJ 中的 @AfterThrowing 属性来生成的 Advice(PS: 若切面方法抛出异常, 则这里的方法就执行)


  3.AspectJAroundAdvice:将执行类 MethodInvocation(MethodInvocation其实就是Pointcut) 进行包裹起来, 并控制其执行的 Advice (其中 Jdk中中 Proxy 使用ReflectiveMethodInvocation, 而 Cglib 则使用 CglibMethodInvocation)


注意,注意,注意:在Proxy中最终执行的其实都是MethodInterceptor,因此这些Advice最终都是交给 AdvisorAdapter -> 将 advice 适配成 MethodInterceptor


MethodInterceptor:


  1. ExposeInvocationInterceptor:将当前 MethodInvocation 放到当前线程对应的 ThreadLoadMap里面的, 这是一个默认的 Interceptor, 在AspectJAwareAdvisorAutoProxy获取何时的 Advisor 时会调用自己的 extendAdvisors 方法, 从而将 ExposeInvocationInterceptor 方法执行链表的第一位。它的实现非常简单:

  private ExposeInvocationInterceptor() {
  }
  @Override
  public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    invocation.set(mi);
    try {
      return mi.proceed();
    }
    finally {
      invocation.set(oldInvocation);
    }
  }


2.SimpleTraceInterceptor:Spring内置了很多日志跟踪的拦截器,父类AbstractTraceInterceptor有多个日志实现:


image.png


CustomizableTraceInterceptor:对方法调用前后拦截一下


public class Main {
    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory(new Person());
        factory.setProxyTargetClass(true); // 强制私用CGLIB 以保证我们的Person方法也能正常调用
        // 记录日志的切面
        CustomizableTraceInterceptoradvice = new CustomizableTraceInterceptor();
        // 切点+通知(注意:此处放的是复合切面)
        Advisor advisor = new DefaultPointcutAdvisor(advice);
        factory.addAdvisor(advisor);
        Person p = (Person) factory.getProxy();
        p.run();
        p.say();
    }
}
输出:
17:28:56.054 [main] TRACE o.s.a.i.CustomizableTraceInterceptor - Entering method 'run' of class [com.fsx.bean.Person]
我在run...
17:28:56.078 [main] TRACE o.s.a.i.CustomizableTraceInterceptor - Exiting method 'run' of class [com.fsx.bean.Person]
17:28:56.079 [main] TRACE o.s.a.i.CustomizableTraceInterceptor - Entering method 'say' of class [com.fsx.bean.Person]
我在say...
17:28:56.079 [main] TRACE o.s.a.i.CustomizableTraceInterceptor - Exiting method 'say' of class [com.fsx.bean.Person]


SimpleTraceInterceptor:正常效果同上,异常也是同样的输出,没CustomizableTraceInterceptor强大

DebugInterceptor:SimpleTraceInterceptor的子类。有个计数器,记录被拦截的次数,且可以这样获取出来advice.getCount()

PerformanceMonitorInterceptor:记录每个方法运行的时长,还是比较有用的.

我在run...
17:37:10.853 [main] TRACE o.s.a.i.PerformanceMonitorInterceptor - StopWatch 'com.fsx.bean.Person.run': running time (millis) = 29
我在say...
17:37:10.854 [main] TRACE o.s.a.i.PerformanceMonitorInterceptor - StopWatch 'com.fsx.bean.Person.say': running time (millis) = 0

3.AfterReturningAdviceInterceptor:这个类其实就是将 AfterReturningAdvice 包裹成 MethodInterceptor 的适配类, 而做对应适配工作的就是 AfterReturningAdviceAdapter


4.MethodBeforeAdviceInterceptor:这个类其实就是将 MethodBeforeAdvice 包裹成 MethodInterceptor 的适配类, 而做对应适配工作的就是 MethodBeforeAdviceAdapter


5.ThrowsAdviceInterceptor:这个类其实就是将 ThrowsAdvice 包裹成 MethodInterceptor 的适配类, 而做对应适配工作的就是 ThrowsAdviceAdapter


6.TransactionInterceptor:这个类就是大名鼎鼎的注解式事务的工具类, 这个类通过获取注解在方法上的 @Transactional 注解的信息来决定是否开启事务的 MethodInterceptor (PS: 在注解式事务编程中将详细叙述)



1、无论通过aop命名空间/AspectJ注解注释的方法, 其最终都将解析成对应的 Advice

2、所有解析的 Advice 最终都将适配成 MethodInterceptor, 并在 JdkDynamicAopProxy/CglibAopProxy中进行统一调用


3、Advisor


Advisor 其实它就是 Pointcut 与 Advice 的组合, Advice 是执行的方法, 而要知道方法何时执行, 则 Advice 必需与 Pointcut 组合在一起, 这就诞生了 Advisor 这个类


打个比方:

Advice表示建议

Pointcut表示建议的地点

Advisor表示建议者(它知道去哪建议,且知道是什么建议)


  1. PointcutAdvisor: 我们在 Spring 中常用的 Advisor, 包含一个 Pointcut 与一个 advice
  2. AspectJPointcutAdvisor: 这个是 Spring 解析 aop 命名空间时生成的 Advisor(与之对应的 Advice 是 AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice, Pointcut 则是AspectJExpressionPointcut), 对于这个类的解析是在 ConfigBeanDefinitionParser
  3. InstantiationModelAwarePointcutAdvisorImpl: 这个Advisor是在Spring解析被 @AspectJ注解注释的类时生成的 Advisor, 而这个 Advisor中的 Pointcut与Advice都是由 ReflectiveAspectJAdvisorFactory 来解析生成的(与之对应的 Advice 是 AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice, Pointcut 则是AspectJExpressionPointcut), 解析的步骤是: AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors() -> BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors() -> ReflectiveAspectJAdvisorFactory.getAdvisors() -> ReflectiveAspectJAdvisorFactory.getAdvisor() 最终生成了 InstantiationModelAwarePointcutAdvisorImpl (当然包括里面的 Pointcut 与 advice 也都是由 ReflectiveAspectJAdvisorFactory 解析生成的)
  4. TransactionAttributeSourceAdvisor: 一个基于 MethodInterceptor(其实是 TransactionInterceptor)与 TransactionAttributeSourcePointcut 的Advisor, 而这个类最常与 TransactionProxyFactoryBean使用
  5. DefaultPointcutAdvisor: 最常用的 Advisor, 在使用编程式aop时, 很多时候会将 Advice / MethodInterceptor 转换成 DefaultPointcutAdvisor
  6. NameMatchMethodPointcutAdvisor: 这个是在使用 NameMatchPointcutAdvisor时创建的 Advisor, 主要是通过 方法名来匹配是否执行 Advice
  7. RegexpMethodPointcutAdvisor: 基于正则表达式来匹配 Pointcut 的 Advisor, 其中的 Pointcut 默认是 JdkRegexpMethodPointcut
  8. Spring 中解析 aop:advisor 时生成的 Advisor, 见 ConfigBeanDefinitionParser.parseAdvisor
  9. BeanFactoryTransactionAttributeSourceAdvisor: 在注解式事务编程时, 主要是由 BeanFactoryTransactionAttributeSourceAdvisor, AnnotationTransactionAttributeSource, TransactionInterceptor 组合起来进行事务的操作(PS: AnnotationTransactionAttributeSource 主要是解析方法上的 @Transactional注解, TransactionInterceptor 是个 MethodInterceptor, 是正真操作事务的地方, 而BeanFactoryTransactionAttributeSourceAdvisor 其实起着组合它们的作用); <- 与之相似的还有 BeanFactoryCacheOperationSourceAdvisor
相关文章
|
4月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
552 0
|
3月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
8月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
1292 13
|
9月前
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
971 4
|
10月前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
390 0
|
10月前
|
负载均衡 Java Nacos
Spring Cloud五大组件
Spring Cloud五大组件
|
5月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
5月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
6月前
|
JSON 前端开发 Java
Spring MVC 核心组件与请求处理机制详解
本文解析了 Spring MVC 的核心组件及请求流程,核心组件包括 DispatcherServlet(中央调度)、HandlerMapping(URL 匹配处理器)、HandlerAdapter(执行处理器)、Handler(业务方法)、ViewResolver(视图解析),其中仅 Handler 需开发者实现。 详细描述了请求执行的 7 步流程:请求到达 DispatcherServlet 后,经映射器、适配器找到并执行处理器,再通过视图解析器渲染视图(前后端分离下视图解析可省略)。 介绍了拦截器的使用(实现 HandlerInterceptor 接口 + 配置类)及与过滤器的区别
560 0