执行 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 这个初始化方法
该方法在初始化之后会调用 applyBeanPostProcessorsAfterInitialization 方法,意思是可以在初始化之后做一些事情,比如创建代理对象
遍历执行所有的 BeanPostProcessor 的初始化后置方法 postProcessAfterInitialization,其中有个实现类叫做 AspectJAwareAdvisorAutoProxyCreator
该方法在它的父类中,主要的实现逻辑是 wrapIfNecessary 这个方法
在这个判断是否需要跳过的逻辑中,如果检查到该 bean 无需被代理那么直接返回,同时里面就包含了缓存 @Aspect 相关信息的内容
在第一次调用 BeanPostProcessor 的后置方法的时候就会进入到该逻辑,将 @Aspect 相关内容进行缓存后续就可以直接使用,原因很简单,实例化第一个对象的时候我们需要知道它是否被代理了,既然要检测那么我们肯定需要先做 @Aspect 检测等相关逻辑,这个时候就进行缓存了便于后续使用
那么这个 Advisor 是什么呢?我们先看测试代码定义了 2 个 Advice
再来看一看 List 内容
相信大家看的很清楚了,就是记录的 Advice 的通知信息,同时附带了@Aspect 的详细信息
我们再来看看在 buildAspectJAdvisors 方法中它是如何构建出来的
第一步,最开始获取到的 aspectBeanNames 肯定是为空的
第二步,通过 BeanFactory 获取到所有的 BeanNames 进行遍历
第三步,获取当前 BeanName 对应的 class 类型进行检测是否标注了 @Aspect 注解,这里就回到了 @Aspect 注解定义的地方,如果没有这个注解后续 AOP 逻辑无从谈起,这就是一个基础注解,它的逻辑非常简单就是通过反射查找类是否实现了 @Aspect 注解
第四步,将 BeanName 放入到 aspectNames 集合中,同时检查实现该注解的类是不是单列如果是的话就构建 MetadataAwareAspectInstanceFactory 这个工厂去获取 Advisors
第一步,拿到切面类,然后根据反射拿到除去标注为 @PointCut 之外的所有方法(包含没有定义注解的普通方法)
第二步,遍历这些方法进行去调用 getAdvisor
首先去检查对应的方法是否实现了上面这些注解如果没有的话则跳过,如果实现了就创建 AspectJExpressionPointcut 对象,然后创建 Advisor 实现对象 InstantiationModelAwarePointcutAdvisorImpl
第三步,将创建好的 Advisor 放入 advisors 集合中返回
最后回到 BeanFactoryAspectJAdvisorsBuilder 的 buildAspectJAdvisors 方法中
将创建好的 Advisor 放入缓存中
总结
我们定义的 @Aspect 注解是基础,然后以 Advice 为维度缓存到对应的 Advisor 对象中,对象中包含了 @Aspect 的相关信息,比如名称、@Pointcut、需要执行代理方法、通知的方式等等