高级的@Aspect切面:我们编程常用的属于高级切面(这里的高级指的是适合编程人员使用)
低级的Advisor切面:这里低级的意思是表示它适合框架内部使用,功能也比较基本
一个@Aspect切面可以包含一组到多组通知和切点,Advisor切面只有一个通知和一个切面,实际上spring在处理@Aspect切面时最终会把高级转换为基本的Advisor切面
演示1 - 代理创建器
初始代码准备(两个目标类 )
写一个@Aspect切面,这里为了体现出一个@Aspect切面可以包含多组切面、通知,这里我们加两个
Advisor切面类,我们用配置类的方式定义:
第一个Bean时我们的切面类(参数需要一个切点,一个通知)
- 切点我们就new一个AspectJExpressionPointcut即可
- 通知稍微复杂,设置为第二个Bean,从第一个Bean的参数这里传进来
注册bean之后打印查看是否注册成功
结果:
AnnotationAwareAspectJAutoProxyCreator
主要作用是将标注有 @Aspect 注解的切面类自动创建为代理类,并注册到 Spring 容器中
在这个类中我们主要看两个比较重要的方法 findEligibleAdvisors 、wrapIfNecessary
这里测试时,因为两个方法都是受保护的,我们将测试代码放在被测试类的同一个包里即可
findEligibleAdvisors
作用是找到有【资格】的 Advisors,也就是匹配上的切面
findEligibleAdvisors 方法主要分为三个步骤:
-
解析出当前 Bean 对象中定义的所有切面(即标注了 @Aspect 注解的类),并将这些切面的 Advisor 执行顺序排序(按照 @Order 中指定的值进行排序)。
-
根据当前 Bean 对象所实现的所有接口,查找与这些接口相关的切入点,并将这些切入点和同类型的 Advisor 组成一个新的 Advisor 列表,将这些 Advisor 存储在 beanFactory 的缓存中。
-
将前两步生成的 Advisor 列表合并为一个完整的 Advisor 列表,并将这个列表缓存到当前 Bean 对象的缓存中。
getBean之后调用方法,该方法返回一个List集合(参数一:待寻找切面的目标类, beanname,这里可以随便写,暂时只与类型有关系,与对象暂时没关系)
结果如下,这里看我们测试的代码中有一个高级界面(包含两个低级切面)一个低级切面,预期应会有3个切面,但是结果却有4个,第一个切面是给所有代理都要加的切面,剩下三个就是我们写的切面
- 第一个为我们自己写的低级切面,后面两个是高级切面转换后的低级切面
往后看也能发现名字,与我们定义的相符
wrapIfNecessary
它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理我们调用之后打印一下类型看看(o1由于匹配到有资格的Advisor,集合不为空,会创建代理)
结果如下(发现结果o1产生代理对象):
我们试着调一下被代理的o1可以发现增强了:
((Target1) o1).foo();
结果:
收获
- AnnotationAwareAspectJAutoProxyCreator 的作用
- 将高级 @Aspect 切面统一为低级 Advisor 切面
- 在合适的时机创建代理
- findEligibleAdvisors 找到有【资格】的 Advisors
- 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如本例 A17 中的 advisor3
- 有【资格】的 Advisor 另一部分是高级的, 由解析 @Aspect 后获得
- wrapIfNecessary
- 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
- 它的调用时机通常在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行