轻轻松松看懂Spring AOP源码


如果对spring的核心容器和JDK动态代理、CGLIB有所了解,接下来再看spring AOP源码会比较容易。文中所有代码片段截图对应的spring版本是5.0。

本文内容曾首发于头条。

首先来看个问题,spring在哪里使用了AOP?spring 实现AOP代码的源头在哪里?

spring AOP运用动态代理技术来创建和初始化代理对象。至于AOP代码的源头和入口,自然是和加载代理类的BeanDefinition和代理对象的创建、初始化有关。

1.spring AOP之加载和解析aop配置

先来看下加载BeanDefinition以及对aop配置的解析,下面是从容器开始启动到解析BeanDefinitions的方法链:

然后我们直接定位到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions,如下图:


轻轻松松看懂Spring AOP源码_子节点


上图中parseCustomElement是对非节点的解析,相关的节点解析自然是走178行代码分支。该分支实际调用的是下图中的代码片段:


轻轻松松看懂Spring AOP源码_子节点_02


1361行代码根据nameSpace匹配相应的handler,aop节点匹配的是右图中的AopNamespaceHandler。1366行的parse调用的是其父类NamespaceHandlerSupport的parse方法,如下图:


轻轻松松看懂Spring AOP源码_spring_03


节点匹配的则是图中右侧的ConfigBeanDefinitionParser。来看下其实现:


轻轻松松看懂Spring AOP源码_spring_04


上述代码106行配置了用于创建代理对象的AspectJAwareAdvisorAutoProxyCreator,我们看完aop配置解析之后再来分析。

节点的子节点是,所以这里走118行的分支。然后就是对的子节点,等的解析。

读到这里应该对AOP配置的解析有了大概的认识。但是你是否想过,解析的结果封装在哪里了?是ParserContext。

ConfigBeanDefinitionParser#parseAspect调用了ConfigBeanDefinitionParser#parseAdvice,来看下其实现:


轻轻松松看懂Spring AOP源码_初始化_05


其中340行是最关键的,可以看到最终是通过创建RootBeanDefinition来封装我们aop节点的配置信息,然后在349行将beanDefinition注册到容器(BeanFactory)。

aop配置的解析就看到这里。下面来看aop中代理对象的创建、实例化等。

2.spring AOP之创建代理

aop创建代理对象的时机是在调用getBean首次从容器中获取bean时。其实现

AbstractBeanFactory#getBean(java.lang.String)调用的是AbstractBeanFactory#doGetBean,下面来看该方法:


轻轻松松看懂Spring AOP源码_加载_06


假设我们要获取的bean是单例并且是首次获取,那么真正创建bean是调用的312行的createBean方法。至此,我们来看一下整个方法链:


轻轻松松看懂Spring AOP源码_父类_07


下面来看下AbstractAutowireCapableBeanFactory#initializeBean:


轻轻松松看懂Spring AOP源码_初始化_08


其中红线框起来的四个方法分别是:

invokeAwareMethods:调用BeanNameAware.setBeanName, BeanFactoryAware.setBeanFactory等

applyBeanPostProcessorsBeforeInitialization:调用BeanPostProcessor.postProcessBeforeInitialization

invokeInitMethods:调用InitializingBean#afterPropertiesSet,调用自定义initMethod

applyBeanPostProcessorsAfterInitialization:调用BeanPostProcessor#postProcessAfterInitialization

之前提到在解析aop配置时向容器注册了AspectJAwareAdvisorAutoProxyCreator,那么此处这个类要派上用场了。我们先来看下这个类的继承体系:


轻轻松松看懂Spring AOP源码_子节点_09


从顶层看,该类主要包含三部分:

ProxyConfig即解析而来的aop配置

Aware部分主要是使其可访问ClassLoader和BeanFactory

BeanPostProcessor则是bean初始化的前置和后置

上面出现的applyBeanPostProcessorsAfterInitialization调用的就是AspectJAwareAdvisorAutoProxyCreator的postProcessAfterInitialization,准确地说是其继承自父类的父类

AbstractAutoProxyCreator.postProcessAfterInitialization。我们来看下该方法调用的

AbstractAutoProxyCreator#wrapIfNecessary,这也是spring判断是否需要创建代理对象的地方:


轻轻松松看懂Spring AOP源码_spring_10


该方法主要分三步:

352行判断该接口或类或方法是否与配置的pointcut的表达式匹配,匹配则需要创建代理对象,不匹配则无需代理。然后如果匹配则返回方法拦截器

355行创建代理对象

357行对代理类进行缓存

我们重点看下createProxy方法实现,方法链如下:


轻轻松松看懂Spring AOP源码_spring_11


有了方法链之后我们直接跳到DefaultAopProxyFactory#createAopProxy,这个方法决定了spring aop动态代理是使用CGLIB还是JDK Proxy:


轻轻松松看懂Spring AOP源码_spring_12


解释下51行if语句中的三个条件:

isOptimize表示让spring自行优化,默认为false

isProxyTargetClass表示是否对类生成代理,默认为false(即使用JDK Proxy,只代理接口)

第三个表示bean没有实现任何接口或者实现的接口是SpringProxy接口

综上,spring AOP默认的创建代理的策略是:

对接口生成代理使用JDK Proxy

对类生成代理使用CGLIB

可通过proxyTargetClass配置是否对类生成代理,为true表示对类生成代理,为false表示不会对类(没有实现SpringProxy以外的接口的类)生成代理

如果觉得写的不错,记得,如果写的不好欢迎批评指正,让我们一起进步!