2019独角兽企业重金招聘Python工程师标准>>>

Spring AOP 源码解析系列,建议大家按顺序阅读,欢迎讨论

  1. Spring源码-AOP(一)-代理模式
  2. Spring源码-AOP(二)-AOP概念
  3. Spring源码-AOP(三)-Spring AOP的四种实现
  4. Spring源码-AOP(四)-ProxyFactory
  5. Spring源码-AOP(五)-ProxyFactoryBean
  6. Spring源码-AOP(六)-自动代理与DefaultAdvisorAutoProxyCreator
  7. 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必须为多例)

    1. CommonsPoolTargetSource:池化TargetSource,每次执行方法时从池中取代理对象,执行完方法再返回池中
    2. ThreadLocalTargetSource:线程级的TargetSource
    3. 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相关推荐

  1. Spring源码——AOP

    前言 内容主要参考自<Spring源码深度解析>一书,算是读书笔记或是原书的补充.进入正文后可能会引来各种不适,毕竟阅读源码是件极其痛苦的事情. 本文主要涉及书中第七章的部分,依照书中内容 ...

  2. [spring源码学习]六、IOC源码-BeanFactory和factory-bean

    https://www.cnblogs.com/jyyzzjl/p/5459335.html 一.代码实例 在我们分析spring的IOC源码的时候,发现除了配置标准的bean,并且通过getBean ...

  3. Spring源码——动态AOP实现流程

    前言 最近回顾了一下Spring源码,准备用思维导图的方式简单的将整个源码内容的流程展示出来,思维导图.图片等文件更新在https://github.com/MrSorrow/spring-frame ...

  4. Spring源码分析(三)

    Spring源码分析 第三章 手写Ioc和Aop 文章目录 Spring源码分析 前言 一.模拟业务场景 (一) 功能介绍 (二) 关键功能代码 (三) 问题分析 二.使用ioc和aop重构 (一) ...

  5. Spring 源码解读第七弹!bean 标签的解析

    Spring 源码解读继续. 本文是 Spring 系列第八篇,如果小伙伴们还没阅读过本系列前面的文章,建议先看看,这有助于更好的理解本文. Spring 源码解读计划 Spring 源码第一篇开整! ...

  6. Spring源码学习1.4 获取XML的验证模式

    Spring5源码分析(008)--IoC篇之加载BeanDefinition:获取XML的验证模式 -- 转载 注:<Spring5源码分析>汇总可参考:Spring5源码分析(002) ...

  7. Spring源码——声明式事务流程

    前言 最近回顾了一下Spring源码,准备用思维导图的方式简单的将整个源码内容的流程展示出来,思维导图.图片等文件更新在https://github.com/MrSorrow/spring-frame ...

  8. Spring源码深度解析,Spring源码以及Bean的生命周期(五)(附代码示例:)

    五)Bean 的生命周期,创建---初始化---销毁的过程 目录 五)Bean 的生命周期,创建---初始化---销毁的过程 一 ,  指定初始化方法 init-method 方法​ 二 ,指定销毁 ...

  9. Spring源码分析——汇总全集

    文章目录 一.背景 二.源码分析目录 三.源码番外篇(补充) 更新时间 更新内容 备注 2022-04-01 Spring源码分析目录和计划 2022-04-10 Spring源码分析一:容器篇-re ...

最新文章

  1. 堆排序算法实现思想个人理解
  2. QQ“远程协助”文字输入技巧
  3. 用VB实现循环队列算法收藏
  4. stay hungry stay foolish原文_弟子规原文+译文+注释
  5. Fedora16安装mplaye和smplayer
  6. eShopOnContainers 看微服务④:Catalog Service
  7. javaScript学习笔记之break 和 continue 语句对比
  8. 天津理工计算机通信工程学院,2018年天津理工大学计算机与通信工程学院811信号与系统考研仿真模拟五套题...
  9. python中decode的用法_python中list怎么使用decode方法设置编码
  10. 关于Ubuntu中 E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)解决方案
  11. 反射 数据类型_这是一份超全面详细的Java反射机制学习指南
  12. 谷歌挖角亚马逊首席AI研究员,推特工程副总裁投奔亚马逊
  13. asp.net 2.0 + sqlserver2005 数据依赖缓存
  14. [leetcode]14. 最长公共前缀
  15. 论文笔记_S2D.15_2016-CVPR_ResNet_用于图像识别的深度残差学习网络
  16. Objective-C 三大要素
  17. 这些年用过的iOS测试框架
  18. Echarts 用GeoJson数据绘制地图
  19. 计算机专业课顺序,计算机专业课程安排顺序 计算机专业课程安排
  20. 【读过的书】《万人如海一身藏》

热门文章

  1. UA MATH571A R语言回归分析实践 多元回归2 医疗费用的决定
  2. 精简版开发工具使用手记(图解)
  3. 学习旧岛小程序 (5) observer 函数中修改属性的值
  4. 水晶报表,解决——提示“您请求的报表需要更多信息.”
  5. 2019年寒假作业1编辑总结
  6. Netbeans and Remote Host for C/C++ Developing
  7. 为博客园博文添加目录的两种方法
  8. jQuery的ajax的post请求json格式无法上传空数组
  9. 如果某一运行的服务在/var/lock/subsys
  10. WebForm与MVC混用