Spring AOP中的Bean是如何被AOP代理的
前面咱已经知道,最终 bean 的初始化会被 BeanPostProcessor 的 postProcessAfterInitialization 处理,进入到 AnnotationAwareAspectJAutoProxyCreator 的 postProcessAfterInitialization 方法中,它又要调用 wrapIfNecessary 方法来尝试创建代理,咱深入方法内部来研究。
1. wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断决定是否是不会被增强的 bean
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 如果上面的判断都没有成立,则决定是否需要进行代理对象的创建
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象的动作
// 注意此处它创建了一个SingletonTargetSource,将bean包装起来了
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}这里前面的筛选过滤懂还是蛮简单的,咱就不关注了,重点是关注一下中间的获取增强器,以及下面的创建代理对象,两个动作。
1.1 getAdvicesAndAdvisorsForBean
这个方法很明显是根据当前正在初始化的 bean ,去匹配获取能切入的增强器,它的源码看上去不复杂:
毫无疑问,核心逻辑是 findEligibleAdvisors 方法咯,继续往里走:
这个方法就很复杂了,尽管只有几行,但都是封装好的方法,咱一个一个的展开来看。
1.1.1 findCandidateAdvisors
又回到 AnnotationAwareAspectJAutoProxyCreator 了:
可以发现,这个方法只是把 SpringFramework 原生的 AOP 增强器,以及 AspectJ 形式封装的增强器都拿出来,仅此而已。
1.1.2 findAdvisorsThatCanApply
所有的增强器获取到之后,下面要去匹配可以切入到当前 bean 的增强器了,咱进入到 findAdvisorsThatCanApply 方法中:
这个方法又交给 AopUtils 执行了,咱继续往里看:
可以发现,整体逻辑分为两个部分,前面是针对引介通知的增强器作筛选,后面是普通的方法通知封装的增强器。
上面的引介增强器的匹配咱就不多研究了,本来平时就用得少,咱主要还是来看对于方法的增强器,它是如何去做匹配的。进入到下面的 canApply 方法中:
从这个逻辑中就可以看出,底层针对不同种的增强器,分别会有不同的判断逻辑。对于方法增强器的判断,它又调用了下面的重载方法:
整体思路还是很清晰的吧,我们要理解的核心部分,是下面的这个双重循环,以此就能判断出来切入点表达式是否能对当前 bean 进行增强了。
Debug 下来,最终发现可以给 OrderService 匹配到的增强器一共有 2 个:( FinanceService 就不看了,因为咱一开始学习的时候,就是拿它举的例子,所有的通知方法都切入它了)

1.1.3 extendAdvisors
这个方法看上去蛮不起眼的,不过小伙伴们有自己 Debug 的话,过了这个方法会发现 eligibleAdvisors 集合中多了一个增强器:

诶?它自己还有偷偷添加增强器啊,那咱看看它干了些啥:
1.1.3.1 extendAdvisors方法的小动作
逻辑不算复杂,它这个方法的关键是,判断当前可用的增强器中有没有 AspectJ 类型的,如果有的话,那就在整个增强器的列表的最前面,添加一个 ExposeInvocationInterceptor.ADVISOR 。
1.1.3.2 ADVISOR是个啥?
那这个 ADVISOR 又是个啥子?咱继续往里走:
哦?合着它是个对所有 bean 都生效的增强器呗?传入的这个 INSTANCE 很明显是单例的设计,那到头来核心还是这个 ExposeInvocationInterceptor 本身。
1.1.3.3 ExposeInvocationInterceptor又是个啥?
那新的问题就来了:ExposeInvocationInterceptor 这玩意的作用是什么呢?
翻开源码的核心 invoke 方法,发现它在向当前线程的 ThreadLocal 中放入了当前正在执行的代理对象的方法执行包装:
每次都在增强器链的第一个执行,并且放入 ThreadLocal 变量中,那这意图就很明显了:它可以让后面的增强器都拿到当前正在执行的 MethodInvocation 。至于哪里会用到 MethodInvocation ,咱目前还没有遇到,后面如果遇到了咱再留意。
或许会有小伙伴产生一个小小的疑惑:那你放就放呗, MethodInvocation oldInvocation = invocation.get(); 这个操作是啥意思?原本就没有,你 get 个什么劲呢???
哎?真的没有吗?如果是一个 AOP 代理对象,调用了另外一个 AOP 代理对象的话,这个过程是在一个线程中执行的呀,那第二个代理对象的方法被调用时,是不是也会经过 ExposeInvocationInterceptor 呢?那是不是从 ThreadLocal 中就可以取出 MethodInvocation 了呢?所以小伙伴们一定要多想一层呀,多实践多思考才会更进步 ~
1.2 createProxy
上面结束之后,所有的增强器也就都准备好了,接下来就是创建代理对象的部分了,咱进入 createProxy 中:
到了这里,咱就可以发现,这里面的逻辑已经基本上处理的差不多了,核心的动作就两个:收集整理要织入到目标对象的通知增强器,以及创建代理对象。前面的那些小细节小伙伴们可以自行研究,相对都是蛮简单的,小册带小伙伴们关注的是这两部分的核心逻辑。
1.2.1 buildAdvisors
源码不算长,里面有一段日志的部分,小册在这里删掉了,咱只关心核心逻辑:
上面整合 SpringFramework 原生 AOP 的内容咱小册就不提及了,毕竟是很久之前用的东西了,咱现在都是 AspectJ 的。在最下面,它有一个 advisorAdapterRegistry.wrap 的方法调用,它是干嘛的呢?咱可以去瞅一眼:
注意这个方法的参数和返回值:它可以是任意类型的入参,但返回的一定是 Advisor ,这也就呼应了 wrap 方法的含义:将可以支持转换 / 包装为 **Advisor** 类型的对象适配成 **Advisor** 。至于它可以适配的类型,内置的只有 MethodInterceptor 和几种原生的 Advice (前面 Spring 原生 AOP 中提到的),不过它提供了一个 AdvisorAdapter 的接口,供我们扩展使用,以此来支持自定义的 Advice 类型。不过我们几乎都没有这么做的,所以这部分小伙伴们知道一下就可以了,没必要深究。
1.2.2 proxyFactory.getProxy
下面就是真正创建代理对象的逻辑了,这个方法又分为两个部分:
咱一一来看。
1.2.2.1 createAopProxy
上面有一个监听器的通知动作,由于这个动作涉及到的监听器 AdvisedSupportListener 只在 ProxyCreatorSupport 这个类中使用,咱们开发也基本不会碰这些东西,所以这个咱可以跳过了,关键的还是下面 getAopProxyFactory().createAopProxy(this); 的执行。
getAopProxyFactory 方法返回的是当前 ProxyCreatorSupport 的成员 aopProxyFactory ,借助 Debug 可以发现它的类型是 DefaultAopProxyFactory 。

进入到它的 createAopProxy 方法中,终于发现了咱熟悉的 jdk 、Cglib 动态代理的字眼了:
至此,咱就知道,使用 jdk 动态代理,还是 Cglib 动态代理,底层的选择是在这里决定的。
1.2.2.2 AopProxy#getProxy
创建完 AopProxy 后,下面就是创建代理对象的动作了,咱以 JdkDynamicAopProxy 为例进去看一下:
看,最底下,咱最最熟悉的 Proxy.newProxyInstance 方法出现了!!!所以由此咱就可以体会到,代理对象的底层创建还是依赖 jdk 动态代理,或者 Cglib 动态代理的核心 API 呀!
至于 Cglib 动态代理的创建,咱就不特别深入了,咱注意一下中间的核心部分即可:
可以看到,这也是对 Cglib 中的 Enhancer 进行操作,核心的思路是不变的,只是框架比咱考虑的更多罢了。
OK ,到此为止,代理对象也就成功创建了,整个 AOP 通知织入的流程也就结束了。
最后更新于
这有帮助吗?