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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 【小家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
相关文章
|
10天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
30天前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
37 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
10天前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
27 5
|
15天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
27 1
|
11天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
24 0
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
1月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
68 2
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
127 9
|
2月前
|
XML 缓存 Java
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
49 10
|
2月前
|
XML 存储 Java
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)