写点什么

【Spring 专场】「AOP 容器」不看源码就带你认识核心流程以及运作原理

作者:浩宇天尚
  • 2022 年 1 月 09 日
  • 本文字数:1916 字

    阅读完需:约 6 分钟

【Spring专场】「AOP容器」不看源码就带你认识核心流程以及运作原理

前提回顾


前一篇文章主要介绍了 spring 核心特性机制的 IOC 容器机制和核心运作原理,接下来我们去介绍另外一个较为核心的功能,那就是 AOP 容器机制,主要负责承接前一篇代理模式机制中动态代理:JDKProxy 和 CglibProxy 的功能机制之后,我们开始研究一下如何实现一下相关的 AOP 容器代理机制的。

AOP 入口机制

如何实现将 Aspectj 的动态 weave 织入到 Spring 容器的 Bean 中?

实现的基本实现原理就是后置处理器:BeanPostProcessor 机制,实现动态化植入机制。

如何实现相关的 Aspectj 的 weave 织入时机

bean 在初始化的时候会进行调用对应的 BeanPostProcessor 的对应的方法会进行织入。

判断的基本流程

主要取决于 wrapIfNecessary 方法:

判断当前的 Bean 是 AOP 的基础设施类型

如果是基础设施类型,则直接回进行返回该 bean 对象,不会进行相关的初始化对应的 aspectj 的动态织入机制。

如果属于定制化的 bean 对象类型

会进行寻找相关的 Bean 对应的何时的加强通知类。

如果对应该对象的通知增强数组集合不为空

则会对该 bean 对象,额外进行增强操作生成相关的代理对象,并返回该执行之后的对象,否则会直接返回该对象即可。

筛选何时的通知器

getAdvicesAndAdvisorsForBean 方法是我们筛选 Advice 增强类的核心方法,主要用于过滤和筛选对应该 bean 的何时的增强器数组信息。

查找对应 Bean 的通知增强器

主要用于调用 AnnotationAwareAspectJAutoProxyCreator 的**findCandidateAdvisors()**方法,其内部会进行先关的核心构建相关的 Aspectj 的类的相关实现操作

构建先关 Aspectj 类 buildAspectJAdvisors 方法

  1. 首先先进行获取先关的所有容器的 BeanName 数据集合

  2. 在根绝上面的 BeanName 名称集合获取相关的 BeanType 类型集合

  3. 根据 BeanType 判断当前的 Bean 是否属于一个 Aspectj 的注解.类,如果不是则类不做任何处理。

构建实际的相关的 Advisors 类机制

advisorsFactory.getAdvisors 获取通知器

切点处理

切点类处理操作到此为止,还不完整接下来才是构建动态代理对象的真正执行操作,


  1. 获取上面操作中获取到的 Aspectj 类中的除了 PointCut 注解修饰的其他的方法列表。

  2. 根据对应的 Aspectj 类和相关的 Advisors 方法列表,创建相关的 Advisor 实现类,其中内部会进行遍历相关上一步的方法列表,并且调用对应的方法 method 对应的 getAdvisor 方法,建立 Advisor 对象。

  3. 创建相关的 AspectJExpressionPointCut 对象,并且从方法里的注解表达式进行解析,这最后设置到对应的门面层的 Advisor 对象实例。

  4. 实际的 Advisor 对象实现类对象的实际:InstantitationModelAwarePoincutAdvisorImpl 实例,并且调用其内部的 instantiateAdvice 方法构建通知机制。

  5. 其内部仍然会调用 getAdvice 方法,并且构建相关的注解的类型创建相应的通知。

筛选何时的通知器并且执行应用

findAdvisorsThatCanApply 方法

扩展相关的筛选出的通知器列表,extendAdvisors 方法,通知器列表首部添加一个 DefaultPointcutAdivosr 类型的通知器,也就是 ExposeInvocationInterceptor.ADVISOR 的实现机制。

创建代理对象

  • jdk 动态代理

  • cglib 动态代理

proxy-target-class

proxy-target-class 的属性值,代表是否可以支持代理实现类,默认采用的 false 代表着,当 bean 有实现接口的时候,会直接采用 jdk 的动态代理机制生成代理对象,如果是 true,则代表着使用 cglib 进行生成代理对象。

例如:
<aop:aspectj-autoproxy proxy-target-class = "true" /></aop>
复制代码
AopProxy 接口
  • CglibAopProxy 接口实现

  • JdkDynamicAopProxy 接口实现

AOP 代理对象调用同类的方法问题解决方案

expose-proxy 作用

前提是必须要配置相关的 expose-proxy 属性配置值为 true,才会进行暴露对应的代理机制。


为了解决目标方法调用同对象中的其他方法,其他方法的切面逻辑是无法实现,因为会涉及到相关的 this 操作而不是 proxy 对象机制。


可以实现使用 AopContext.currentProxy()强制转换为当前的代理对象。


拦截器链路执行

intercept 方法机制

获取相关的对应方法的拦截器栈链路,如果没有获取到相关的缓存链路,则会直接调用相关的 getInterceptorsAndDynamicInterceptorAdvice 获取先关的拦截器链。

方法拦截器相关的拦截操作连接点

会进行先关的 PointcutAdvisor 类型通知器,这里会调用相关的通知器所持有的切点(Pointcut)对类和方法进行匹配,匹配冲过这说明相关的向当前的方法进行织入逻辑控制。此外还会通过 geIntercptors()方法对非 MethodIntercptor 类型的通知进行转换。返回相关的拦截器数组,并且随后存入缓存中。

执行目标方法的方式

如果拦截器为空

则会直接通过代理机制的反射控制进行调用执行即可。

如果不为空

则例如 jdkDynamicAutoProxy 对象进行调用构建 ReflectiveMethodInvocation 对象,例如它的 process 方法启动拦截器栈的 invoke 方法。


  • invoke:执行拦截器栈

  • invokeJoinpoin():执行目标方法


处理返回值,并且返回该值。

敬请期待下篇


MVC 容器模型机制

发布于: 2022 年 01 月 09 日阅读数: 55
用户头像

浩宇天尚

关注

🏆InfoQ写作平台-签约作者🏆 2020.03.25 加入

【个人简介】酷爱计算机科学、醉心编程技术、喜爱健身运动、热衷悬疑推理的“极客达人” 【技术格言】任何足够先进的技术都与魔法无异 【技术范畴】Java领域、Spring生态、MySQL专项、微服务/分布式体系和算法设计等

评论

发布
暂无评论
【Spring专场】「AOP容器」不看源码就带你认识核心流程以及运作原理_spring_浩宇天尚_InfoQ写作社区