Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator
2019独角兽企业重金招聘Python工程师标准>>>
Spring AOP 源码解析系列,建议大家按顺序阅读,欢迎讨论
- Spring源码-AOP(一)-代理模式
- Spring源码-AOP(二)-AOP概念
- Spring源码-AOP(三)-Spring AOP的四种实现
- Spring源码-AOP(四)-ProxyFactory
- Spring源码-AOP(五)-ProxyFactoryBean
- Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator
- Spring源码-AOP(七)-整合AspectJ
框架存在的意义,简单来说就是将复杂的底层实现封装起来,并提供便捷的外部接口供用户使用。对于Spring AOP而言,不论是ProxyFactory还是ProxyFactoryBean,都不能满足实际业务中复杂的应用,用户不可能对每个使用AOP代理的类进行配置。这时通过一定规则自动发现和代理自然应运而生。在spring-aop工程的autoproxy目录构成了Spring AOP自动代理的基础,AbstractAutoProxyCreator是自动代理实现的抽象基类,BeanNameAutoProxyCreator和DefaultAdvisorAutoProxyCreator则是Spring提供的两个实现。
自动代理的实现原理同ProxyFactoryBean中使用FactoryBean扩展不同,而是通过BeanPostProcessor扩展对Bean对象的创建过程进行控制来实现AOP代理。抽象基类AbstractAutoProxyCreator实现了BeanPostProcessor的子接口SmartInstantiationAwareBeanPostProcessor。先来了解下这个子接口。
1.扩展接口SmartInstantiationAwareBeanPostProcessor
我们常提及的BeanPostProcessor扩展并不是只有BeanPostProcessor一个接口,而是由其形成的多层接口体系,对Bean对象在IOC容器的创建过程的各个节点扩展形成的体系。这里只展示下SmartInstantiationAwareBeanPostProcessor的类结构。
BeanPostProcessor
- postProcessBeforeInitialization 初始化前扩展(执行init-method前)
- postProcessAfterInitialization 初始化后扩展(执行init-method后)
InstantiationAwareBeanPostProcessor
- postProcessBeforeInstantiation 对象实例化前扩展
- postProcessAfterInstantiation 对象实例化后扩展
- postProcessPropertyValues 属性依赖注入前扩展
SmartInstantiationAwareBeanPostProcessor
- predictBeanType 预测bean的类型,在beanFactory的getType时被调用
- determineCandidateConstructors 对象实例化时决定要使用的构造函数时被调用
- getEarlyBeanReference 循环依赖处理时获取Early对象引用时被调用
而对于Spring AOP的自动代理,处理的阶段有两个,对象实例化前扩展和初始化后扩展。
2.自动代理基类AbstractAutoProxyCreator
在对象实例化前(postProcessBeforeInstantiation)的扩展中,主要对配置了customTargetSourceCreators属性的情况进行处理,而默认的处理都是在初始化后(postProcessAfterInitialization)扩展里执行的。
对象实例化前postProcessBeforeInstantiation
所谓的customTargetSourceCreators属性是在AbstractAutoProxyCreator中的一个TargetSourceCreator数组,用来对代理对象target的封装类TargetSource的生成进行自定义。spring内置的TargetSourceCreator有两个:LazyInitTargetSourceCreator和QuickTargetSourceCreator。
LazyInitTargetSourceCreator:创建的代理对象并没有初始化,直到第一次调用时才进行初始化
QuickTargetSourceCreator:根据beanName的不同前缀创建三种常用的TargetSource类型(bean必须为多例)
- CommonsPoolTargetSource:池化TargetSource,每次执行方法时从池中取代理对象,执行完方法再返回池中
- ThreadLocalTargetSource:线程级的TargetSource
- PrototypeTargetSource:多例TargetSource,每次执行方法创建新的代理对象,执行完销毁该对象
来看下核心代码
if (beanName != null) {// 获取自定义TargetSourceTargetSource targetSource = getCustomTargetSource(beanClass, beanName);if (targetSource != null) {this.targetSourcedBeans.add(beanName);// 获取拦截器Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);// 创建代理对象Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}
}
第一步获取定义TargetSource,即遍历所有自定义TargetSourceCreator,调用getTargetSource方法返回TargetSource。
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {// We can't create fancy target sources for directly registered singletons.if (this.customTargetSourceCreators != null &&this.beanFactory != null && this.beanFactory.containsBean(beanName)) {for (TargetSourceCreator tsc : this.customTargetSourceCreators) {TargetSource ts = tsc.getTargetSource(beanClass, beanName);if (ts != null) {// Found a matching TargetSource.if (logger.isDebugEnabled()) {logger.debug("TargetSourceCreator [" + tsc +" found custom TargetSource for bean with name '" + beanName + "'");}return ts;}}}// No custom TargetSource found.return null;
}
第二步获取拦截器由子类实现,根据不同的方式获取当前bean的拦截器,在后文以子类DefaultAdvisorAutoProxyCreator为例详细介绍。
第三步创建代理对象,通过创建ProxyFactory的方式完成,原理细节见ProxyFactory,来简单看下它的实现。
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {ProxyFactory proxyFactory = new ProxyFactory();// copy代理配置,如proxyTargetClass,exposeProxy等proxyFactory.copyFrom(this);// proxyTargetClass=false时if (!proxyFactory.isProxyTargetClass()) {// 再次确认是否要代理类对象if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}// 不需要则获取其代理接口集合else {evaluateProxyInterfaces(beanClass, proxyFactory);}}// 将所有拦截器封装成AdvisorAdvisor[] advisors = buildAdvisors(beanName, specificInterceptors);for (Advisor advisor : advisors) {proxyFactory.addAdvisor(advisor);}proxyFactory.setTargetSource(targetSource);// 扩展点,支持子类对ProxyFacory扩展customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}// 创建代理对象return proxyFactory.getProxy(getProxyClassLoader());
}
可以说逻辑非常清晰,最后使用ProxyFactory创建代理对象也是使用ProxyFactory统一的API。如果最终返回的代理对象不为空,则直接返回代理对象,不再执行IOC中的对象属性注入和初始化等操作了。
初始化后(postProcessAfterInitialization)
如果并没有设置自定义TargetSourceCreator,代理对象就会在原始对象初始化完成后创建。
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.contains(cacheKey)) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}
wrapIfNecessary方法执行代理的核心操作。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (beanName != null && this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}// AOP体系的子类不被代理(Advisor,Advice等)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);// 创建代理对象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;
}
实现过程基本同之前的一直,由子类返回拦截器集合,创建ProxyFactory对象进行代理。
3.默认自动代理类DefaultAdvisorAutoProxyCreator
在基类AbstractAutoProxyCreator中通过BeanPostProcessor扩展的方式,使得bean在创建过程中完成被代理。代理的框架已有AbstractAutoProxyCreator基本完成,留给子类的是获取拦截器getAdvicesAndAdvisorsForBean方法的具体实现。我们以DefaultAdvisorAutoProxyCreator为例,了解下Spring AOP是如何完成自动发现和过滤切面的。
DefaultAdvisorAutoProxyCreator的获取拦截器实现其实由其抽象基类AbstractAdvisorAutoProxyCreator实现。
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);if (advisors.isEmpty()) {return DO_NOT_PROXY;}return advisors.toArray();
}
实际操作有findEligibleAdvisors执行
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {// 寻找所有Advisor候选者List<Advisor> candidateAdvisors = findCandidateAdvisors();// 获取匹配当前bean的AdvisorList<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {// 对Advisor排序eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;
}
主要过程分为两步,第一步寻找所有Advisor候选者,即自动发现切面,第二部筛选当前bean的Advisor。
findCandidateAdvisors由BeanFactoryAdvisorRetrievalHelper帮助类执行,原理就是从BeanFactory及其所有父级BeanFactory中寻找类型为Advisor的类,并执行getBean实例化。
public List<Advisor> findAdvisorBeans() {// Determine list of advisor bean names, if not cached already.String[] advisorNames = null;synchronized (this) {advisorNames = this.cachedAdvisorBeanNames;if (advisorNames == null) {// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the auto-proxy creator apply to them!// 寻找Advisor类型的beanadvisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);this.cachedAdvisorBeanNames = advisorNames;}}if (advisorNames.length == 0) {return new LinkedList<Advisor>();}List<Advisor> advisors = new LinkedList<Advisor>();for (String name : advisorNames) {if (isEligibleBean(name)) {if (this.beanFactory.isCurrentlyInCreation(name)) {if (logger.isDebugEnabled()) {logger.debug("Skipping currently created advisor '" + name + "'");}}else {try {// getBean实例化advisors.add(this.beanFactory.getBean(name, Advisor.class));}catch (BeanCreationException ex) {Throwable rootCause = ex.getMostSpecificCause();if (rootCause instanceof BeanCurrentlyInCreationException) {BeanCreationException bce = (BeanCreationException) rootCause;if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {if (logger.isDebugEnabled()) {logger.debug("Skipping advisor '" + name +"' with dependency on currently created bean: " + ex.getMessage());}// Ignore: indicates a reference back to the bean we're trying to advise.// We want to find advisors other than the currently created bean itself.continue;}}throw ex;}}}}return advisors;
}
findAdvisorsThatCanApply筛选Advisor是由AopUtils类实现。对不同类型的Advisor进行不同的处理,如IntroductionAdvisor和PointcutAdvisor。
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {if (candidateAdvisors.isEmpty()) {return candidateAdvisors;}List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();for (Advisor candidate : candidateAdvisors) {if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {eligibleAdvisors.add(candidate);}}boolean hasIntroductions = !eligibleAdvisors.isEmpty();for (Advisor candidate : candidateAdvisors) {if (candidate instanceof IntroductionAdvisor) {// already processedcontinue;}// 匹配Advisor是否适用当前beanif (canApply(candidate, clazz, hasIntroductions)) {eligibleAdvisors.add(candidate);}}return eligibleAdvisors;
}
其中canApply方法执行实际的匹配操作,细节部分主要是对切入点Pointcut和bean的匹配,有兴趣的可以自己深入研究其匹配过程。
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {if (advisor instanceof IntroductionAdvisor) {return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);}else if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pca = (PointcutAdvisor) advisor;return canApply(pca.getPointcut(), targetClass, hasIntroductions);}else {// It doesn't have a pointcut so we assume it applies.return true;}
}
至此也就完成了bean适用的Advisor切面的自动发现与筛选,最后由ProxyFactory完成代理创建。
4.AOP中的循环依赖
在看自动代理源码的过程中,突然注意到SmartInstantiationAwareBeanPostProcessor接口中的getEarlyBeanReference方法,它是Spring处理循环依赖时返回**未创建完(只实例化未做依赖注入)**Bean的扩展。关于循环依赖可以去Bean的循环依赖一章去详细了解,这里只做简单的说明。
有两个单例Bean,A和B,A中引用了B,B中引用了A。Spring对这种相互依赖做了特殊的处理,即在对象实例化后缓存一份key为beanName的ObjectFactory,ObjectFactory中的getObject方法返回当前创建对象的引用。
// 支持单例依赖循环
if (earlySingletonExposure) {// 添加Early对象缓存addSingletonFactory(beanName, new ObjectFactory<Object>() {[@Override](https://my.oschina.net/u/1162528)public Object getObject() throws BeansException {return getEarlyBeanReference(beanName, mbd, bean);}});
}
这里假设先创建A对象实例,当A进行依赖注入时,需要B对象,则会通过getBean方法创建B对象。此时A并没有创建完成,但在Early缓存中存有A的引用,因而当B对象进行依赖注入A时,直接返回A对象的Early引用,从而不会造成陷入无休止的依赖注入循环中。
在getEarlyBeanReference方法中,不仅只是返回对象引用,还有一个扩展点,支持SmartInstantiationAwareBeanPostProcessor接口中的getEarlyBeanReference方法对返回的对象引用进行修改。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 扩展点,对Early对象进行修改exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);if (exposedObject == null) {return exposedObject;}}}}return exposedObject;
}
回到AOP的自动代理上,在AbstractAutoProxyCreator中实现了getEarlyBeanReference扩展
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.contains(cacheKey)) {this.earlyProxyReferences.add(cacheKey);}return wrapIfNecessary(bean, beanName, cacheKey);
}
这里将标识唯一bean的cacheKey添加到earlyProxyReferences中,在之后bean的初始化中将很有用。然后执行wrapIfNecessary返回bean的代理对象,因而如果存在循环依赖,则依赖注入的就是真正的代理对象。
在对象执行完依赖注入后,进行初始化操作,会调用初始化后扩展postProcessAfterInitialization方法,再来关注下AbstractAutoProxyCreator此方法的实现。
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);// 判断early引用中是否包含cacheKeyif (!this.earlyProxyReferences.contains(cacheKey)) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}
它判断了earlyProxyReferences中不包含当前bean的cacheKey才会执行代理操作,也就是说,如果存在循环依赖时,代理对象在getEarlyBeanReference时就创建了,而在初始化后直接跳过了,返回的bean是原始的对象。
你可能会问,既然这里返回的不是代理对象,那代理对象最后是怎样返回的呢?
Spring在对象进行初始化后,对存在循环依赖的又做了巧妙的处理。
if (earlySingletonExposure) {// 如果存在循环依赖,则返回的为代理对象Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {// 循环依赖下,经过初始化后的对象同原始对象一致// 因而将代理对象赋给最终返回的对象引用if (exposedObject == bean) {exposedObject = earlySingletonReference;}}
}
这里的设计很是巧妙,需要结合依赖循环的处理,AOP对象的处理统一来理解。同时对循环依赖时,不直接缓存对象,而是通过ObjectFactory的方式有了更深的理解。有兴趣的同学可以反复琢磨一下。
2017/12/24更新
回头再看这个循环依赖的点,还是花了一点时间来回翻了下源码才理解,因此再补充记录下。getSingleton(beanName, false)方法,当不存在循环依赖时,会返回null,而存在循环依赖时,返回的是ObjectFactory的getEarlyBeanReference方法返回的对象。原始的bean对象经过getEarlyBeanReference方法后,可能存在SmartInstantiationAwareBeanPostProcessor处理器,在其getEarlyBeanReference方法中被改变了,比如AbstractAutoProxyCreator中会返回代理对象。而在AbstractAutoProxyCreator的实现中,使用cacheKey保证了生成的代理对象是单例的。因此当if (exposedObject == bean)判断时会返回true,从而getBean方法返回的对象就是真正的代理对象。此时还有一个疑问,代理对象并没有进行属性的依赖注入以及init-method等的初始化啊?其实代理对象没有必要去复制原始对象的内部结构,因为它持有原始对象的引用,并且实际调用方法是交由原始对象去处理的。
总结
Spring AOP的自动代理,它同ProxyFactoryBean采用了不同的扩展方式。FactoryBean的扩展思路非常清晰,在工厂ProxyFactoryBean创建完成后直接根据其配置动态生成不同的代理对象,适用于简单的配置,但在ApplicationContext高级容器中,就需要通过BeanPostProcessor扩展进行更细粒度的操作,从而支持复杂的业务配置。而接下来要讨论的AspectJ整合Spring的基础实现,就来自于Spring AOP的自动代理。
转载于:https://my.oschina.net/u/2377110/blog/1517915
Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator相关推荐
- Spring源码——AOP
前言 内容主要参考自<Spring源码深度解析>一书,算是读书笔记或是原书的补充.进入正文后可能会引来各种不适,毕竟阅读源码是件极其痛苦的事情. 本文主要涉及书中第七章的部分,依照书中内容 ...
- [spring源码学习]六、IOC源码-BeanFactory和factory-bean
https://www.cnblogs.com/jyyzzjl/p/5459335.html 一.代码实例 在我们分析spring的IOC源码的时候,发现除了配置标准的bean,并且通过getBean ...
- Spring源码——动态AOP实现流程
前言 最近回顾了一下Spring源码,准备用思维导图的方式简单的将整个源码内容的流程展示出来,思维导图.图片等文件更新在https://github.com/MrSorrow/spring-frame ...
- Spring源码分析(三)
Spring源码分析 第三章 手写Ioc和Aop 文章目录 Spring源码分析 前言 一.模拟业务场景 (一) 功能介绍 (二) 关键功能代码 (三) 问题分析 二.使用ioc和aop重构 (一) ...
- Spring 源码解读第七弹!bean 标签的解析
Spring 源码解读继续. 本文是 Spring 系列第八篇,如果小伙伴们还没阅读过本系列前面的文章,建议先看看,这有助于更好的理解本文. Spring 源码解读计划 Spring 源码第一篇开整! ...
- Spring源码学习1.4 获取XML的验证模式
Spring5源码分析(008)--IoC篇之加载BeanDefinition:获取XML的验证模式 -- 转载 注:<Spring5源码分析>汇总可参考:Spring5源码分析(002) ...
- Spring源码——声明式事务流程
前言 最近回顾了一下Spring源码,准备用思维导图的方式简单的将整个源码内容的流程展示出来,思维导图.图片等文件更新在https://github.com/MrSorrow/spring-frame ...
- Spring源码深度解析,Spring源码以及Bean的生命周期(五)(附代码示例:)
五)Bean 的生命周期,创建---初始化---销毁的过程 目录 五)Bean 的生命周期,创建---初始化---销毁的过程 一 , 指定初始化方法 init-method 方法 二 ,指定销毁 ...
- Spring源码分析——汇总全集
文章目录 一.背景 二.源码分析目录 三.源码番外篇(补充) 更新时间 更新内容 备注 2022-04-01 Spring源码分析目录和计划 2022-04-10 Spring源码分析一:容器篇-re ...
最新文章
- 堆排序算法实现思想个人理解
- QQ“远程协助”文字输入技巧
- 用VB实现循环队列算法收藏
- stay hungry stay foolish原文_弟子规原文+译文+注释
- Fedora16安装mplaye和smplayer
- eShopOnContainers 看微服务④:Catalog Service
- javaScript学习笔记之break 和 continue 语句对比
- 天津理工计算机通信工程学院,2018年天津理工大学计算机与通信工程学院811信号与系统考研仿真模拟五套题...
- python中decode的用法_python中list怎么使用decode方法设置编码
- 关于Ubuntu中 E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)解决方案
- 反射 数据类型_这是一份超全面详细的Java反射机制学习指南
- 谷歌挖角亚马逊首席AI研究员,推特工程副总裁投奔亚马逊
- asp.net 2.0 + sqlserver2005 数据依赖缓存
- [leetcode]14. 最长公共前缀
- 论文笔记_S2D.15_2016-CVPR_ResNet_用于图像识别的深度残差学习网络
- Objective-C 三大要素
- 这些年用过的iOS测试框架
- Echarts 用GeoJson数据绘制地图
- 计算机专业课顺序,计算机专业课程安排顺序 计算机专业课程安排
- 【读过的书】《万人如海一身藏》
热门文章
- UA MATH571A R语言回归分析实践 多元回归2 医疗费用的决定
- 精简版开发工具使用手记(图解)
- 学习旧岛小程序 (5) observer 函数中修改属性的值
- 水晶报表,解决——提示“您请求的报表需要更多信息.”
- 2019年寒假作业1编辑总结
- Netbeans and Remote Host for C/C++ Developing
- 为博客园博文添加目录的两种方法
- jQuery的ajax的post请求json格式无法上传空数组
- 如果某一运行的服务在/var/lock/subsys
- WebForm与MVC混用