轻轻松松看懂Spring AOP源码
https://baijiahao.baidu.com/s?id=1596466083334197175&wfr=spider&for=pc
如果对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,如下图:
上图中parseCustomElement是对非节点的解析,相关的节点解析自然是走178行代码分支。该分支实际调用的是下图中的代码片段:
1361行代码根据nameSpace匹配相应的handler,aop节点匹配的是右图中的AopNamespaceHandler。1366行的parse调用的是其父类NamespaceHandlerSupport的parse方法,如下图:
节点匹配的则是图中右侧的ConfigBeanDefinitionParser。来看下其实现:
上述代码106行配置了用于创建代理对象的AspectJAwareAdvisorAutoProxyCreator,我们看完aop配置解析之后再来分析。
节点的子节点是,所以这里走118行的分支。然后就是对的子节点,等的解析。
读到这里应该对AOP配置的解析有了大概的认识。但是你是否想过,解析的结果封装在哪里了?是ParserContext。
ConfigBeanDefinitionParser#parseAspect调用了ConfigBeanDefinitionParser#parseAdvice,来看下其实现:
其中340行是最关键的,可以看到最终是通过创建RootBeanDefinition来封装我们aop节点的配置信息,然后在349行将beanDefinition注册到容器(BeanFactory)。
aop配置的解析就看到这里。下面来看aop中代理对象的创建、实例化等。
2.spring AOP之创建代理
aop创建代理对象的时机是在调用getBean首次从容器中获取bean时。其实现
AbstractBeanFactory#getBean(java.lang.String)调用的是AbstractBeanFactory#doGetBean,下面来看该方法:
假设我们要获取的bean是单例并且是首次获取,那么真正创建bean是调用的312行的createBean方法。至此,我们来看一下整个方法链:
下面来看下AbstractAutowireCapableBeanFactory#initializeBean:
其中红线框起来的四个方法分别是:
invokeAwareMethods:调用BeanNameAware.setBeanName, BeanFactoryAware.setBeanFactory等
applyBeanPostProcessorsBeforeInitialization:调用BeanPostProcessor.postProcessBeforeInitialization
invokeInitMethods:调用InitializingBean#afterPropertiesSet,调用自定义initMethod
applyBeanPostProcessorsAfterInitialization:调用BeanPostProcessor#postProcessAfterInitialization
之前提到在解析aop配置时向容器注册了AspectJAwareAdvisorAutoProxyCreator,那么此处这个类要派上用场了。我们先来看下这个类的继承体系:
从顶层看,该类主要包含三部分:
ProxyConfig即解析而来的aop配置
Aware部分主要是使其可访问ClassLoader和BeanFactory
BeanPostProcessor则是bean初始化的前置和后置
上面出现的applyBeanPostProcessorsAfterInitialization调用的就是AspectJAwareAdvisorAutoProxyCreator的postProcessAfterInitialization,准确地说是其继承自父类的父类
AbstractAutoProxyCreator.postProcessAfterInitialization。我们来看下该方法调用的
AbstractAutoProxyCreator#wrapIfNecessary,这也是spring判断是否需要创建代理对象的地方:
该方法主要分三步:
352行判断该接口或类或方法是否与配置的pointcut的表达式匹配,匹配则需要创建代理对象,不匹配则无需代理。然后如果匹配则返回方法拦截器
355行创建代理对象
357行对代理类进行缓存
我们重点看下createProxy方法实现,方法链如下:
有了方法链之后我们直接跳到DefaultAopProxyFactory#createAopProxy,这个方法决定了spring aop动态代理是使用CGLIB还是JDK Proxy:
解释下51行if语句中的三个条件:
isOptimize表示让spring自行优化,默认为false
isProxyTargetClass表示是否对类生成代理,默认为false(即使用JDK Proxy,只代理接口)
第三个表示bean没有实现任何接口或者实现的接口是SpringProxy接口
综上,spring AOP默认的创建代理的策略是:
对接口生成代理使用JDK Proxy
对类生成代理使用CGLIB
可通过proxyTargetClass配置是否对类生成代理,为true表示对类生成代理,为false表示不会对类(没有实现SpringProxy以外的接口的类)生成代理
如果觉得写的不错,记得,如果写的不好欢迎批评指正,让我们一起进步!