专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

Spring AOP 源码解析(一),Advisors 的构建和缓存

执行 AOP 逻辑时需要为目标对象创建代理

如果一个类没有需要执行任何 AOP 逻辑那么它就无需代理,直接执行即可。

但是当一个类需要执行 AOP 逻辑的时候,比如类中的方法被 @Pointcut 拦截到了就需要为目标对象创建代理对象来执行对应的切面逻辑

Spring AOP 基本概念介绍

可能有些读者这些概念记了又忘记,因为官方介绍过于标准化,我来通俗的介绍下

  • 切面(Aspect),只有被该注解定义了的类才具备拦截的可能,不然后续 Advice、Pointcut 这些都无从谈起,他们都是基于切面的
  • 通知(Advice),在执行目标方法的时候(执行前、后)需要执行的逻辑,比如我们要为 userService.login() 记录登陆日志这个就是我们的目标方法
    • 前置通知(Before Advice),在目标方法方法执行之前
    • 后置通知(After Advice),在目标方法执行之后
    • 环绕通知(Around Advice),通过传入参数可以做到同时在方法前后执行逻辑
  • 连接点(JointPoint),任何一个方法的执行我们可以看到是一个 JointPoint
  • 切入点(Pointcut),检查 JointPoint 是否满足 @Pointcut 的匹配规则,如果满足的话该方法就是一个 PointCut,也就是需要被代理的目标方法

如果说这些定义还有不清楚的也没有关系,后面源码分析的时候我会 DEBUG 他们的具体内容出来到时候一看就明白了

源码分析,找到 @Aspect 切面类的相关信息并缓存

要想知道类是否需要被代理的话我们的首先将 @Aspect 相关信息进行缓存,然后在其它 Bean 实例化后去检查其是否需要被代理

接着上一节的内容,在 AbstractAutowireCapableBeanFactory 这个类中的 doCreateBean 方法中会调用 initializeBean 这个初始化方法

57_1.png该方法在初始化之后会调用 applyBeanPostProcessorsAfterInitialization 方法,意思是可以在初始化之后做一些事情,比如创建代理对象

57_2.png

遍历执行所有的 BeanPostProcessor 的初始化后置方法 postProcessAfterInitialization,其中有个实现类叫做 AspectJAwareAdvisorAutoProxyCreator

57_3.png

57_4.png该方法在它的父类中,主要的实现逻辑是 wrapIfNecessary 这个方法

57_5.png

在这个判断是否需要跳过的逻辑中,如果检查到该 bean 无需被代理那么直接返回,同时里面就包含了缓存 @Aspect 相关信息的内容

57_6.png

57_7.png

在第一次调用 BeanPostProcessor 的后置方法的时候就会进入到该逻辑,将 @Aspect 相关内容进行缓存后续就可以直接使用,原因很简单,实例化第一个对象的时候我们需要知道它是否被代理了,既然要检测那么我们肯定需要先做 @Aspect 检测等相关逻辑,这个时候就进行缓存了便于后续使用

那么这个 Advisor 是什么呢?我们先看测试代码定义了 2 个 Advice

57_8.png再来看一看 List 内容

57_9.png

57_10.png相信大家看的很清楚了,就是记录的 Advice 的通知信息,同时附带了@Aspect 的详细信息

我们再来看看在 buildAspectJAdvisors 方法中它是如何构建出来的

57_11.png第一步,最开始获取到的 aspectBeanNames 肯定是为空的

第二步,通过 BeanFactory 获取到所有的 BeanNames 进行遍历

第三步,获取当前 BeanName 对应的 class 类型进行检测是否标注了 @Aspect 注解,这里就回到了 @Aspect 注解定义的地方,如果没有这个注解后续 AOP 逻辑无从谈起,这就是一个基础注解,它的逻辑非常简单就是通过反射查找类是否实现了 @Aspect 注解

57_12.png第四步,将 BeanName 放入到 aspectNames 集合中,同时检查实现该注解的类是不是单列如果是的话就构建 MetadataAwareAspectInstanceFactory 这个工厂去获取 Advisors

57_13.png

57_14.png第一步,拿到切面类,然后根据反射拿到除去标注为 @PointCut 之外的所有方法(包含没有定义注解的普通方法)

第二步,遍历这些方法进行去调用 getAdvisor

57_15.png

57_16.png

57_17.png

57_18.png首先去检查对应的方法是否实现了上面这些注解如果没有的话则跳过,如果实现了就创建 AspectJExpressionPointcut 对象,然后创建 Advisor 实现对象 InstantiationModelAwarePointcutAdvisorImpl

57_19.png

第三步,将创建好的 Advisor 放入 advisors 集合中返回

最后回到 BeanFactoryAspectJAdvisorsBuilder 的 buildAspectJAdvisors 方法中

57_20.png将创建好的 Advisor 放入缓存中

总结

我们定义的 @Aspect 注解是基础,然后以 Advice 为维度缓存到对应的 Advisor 对象中,对象中包含了 @Aspect 的相关信息,比如名称、@Pointcut、需要执行代理方法、通知的方式等等

57_21.png

文章永久链接:https://tech.souyunku.com/26040

未经允许不得转载:搜云库技术团队 » Spring AOP 源码解析(一),Advisors 的构建和缓存

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们