Spring AOP部分源码分析
Spring源码流程分析-AOP相关
根据Spring源码整理,其中Calculator为自定义的实现方法。
AnnotationConfigApplicationContext()加载配置类的流程
- register()传入配置类,准备IoC容器
- 注册配置类之后,refresh()刷新创建的容器
- invokeBeanFactoryPostProcessors()
- registerBeanPostProcessors()注册Bean的后置处理器以拦截bean
- 先获取IoC容器中已经定义了的需要创建的BeanProceesorNames
- 注册BeanPostProcessorChecker,该检查器在BeanPostProcessor实例化期间创建bean时记录信息消息,例如,当bean不符合所有BeanPostProcessor的处理条件时进行记录。
- 将BeanPostProcessor按照实现的PriorityOrdered,Ordered和其他接口进行分类
- 首先注册实现PriorityOrdered接口的BeanPostProccessor
- 然后注册实现了Ordered接口的BeanPostProccessor
- 根据PostProcessorName获取Bean
- 创建Bean实例(这里获取的是一个BeanWrap对象,并不是Bean)
- 给BeanPostProcessors返回一个代理对象替代目标bean实例的机会
- 真正创建Bean实例(PostProcessor本身也是一个Bean实例)
- 创建一个BeanWrapper(bean包装类)
- 创建Bean实例(输入internalAutoProxyCreator)
- 获取到真实的beanClass(这里是AnnotationAwareAspectJAutoProxyCreator)
- 如果没有特殊的处理,仅适用无参构造方法进行实例化
- 先获取实例化的策略(通过getInstantiationStrategy()),用以实例化Bean
- 使用CGLIB进行实例化(如果没有重写的情况下使用)
- 使用反射机制进行实例化
- 先获取实例化的策略(通过getInstantiationStrategy()),用以实例化Bean
- 通过BeanWrap获取包装的bean对象
- 通过BeanWrap获取包装的bean对象的类型
- 后置处理器可以修改合并的bean定义。
- 获取定义好的全部PostProcessor,如果有MergedBeanDefinitionPostProcessor处理器,则进行合并。(eg.合并了ApplicationListenerDetector)
- 给bean的各种属性赋值(populateBean)
- 初始化Bean(initializeBean)
- 调用Aware方法
- 对实现了BeanNameAware接口的bean进行设置beanName
- 对实现了BeanClassLoaderAware接口的Bean设置beanClassLoader
- 对实现了BeanFactoryAware接口的Bean设置beanFactory
- 在初始化前调用BeanPostProcessors处理器(applyBeanPostProcessorBeforeInitialization)
- 获取全部的BeanPostProcessors
- 依次执行其中的postProcessBeforeInitialization()方法
- 调用AwareInterface方法:
- ApplicationContextAwareProcessor时的AwareInterface方法如下:
- EnvironmentAware->setEnvironment()
- EmbeddedValueResolverAware->setEmbeddedValueResolver()
- ResourceLoaderAware->setResourceLoader()
- ApplicationEventPublisherAware->setApplicationEventPublisher()
- MessageSourceAware->setMessageSource()
- ApplicationContextAware->setApplicationContext()
- 调用Init方法:
- 先判断是否是InitializingBean(如果是,执行以下内容)
- 获取initMethodName
- 调用自定义的初始化方法
- 在初始化方法后调用BeanPostProcessors处理器(applyBeanPostProcesssorAfterInitialization)
- 调用Aware方法
- 创建Bean实例(这里获取的是一个BeanWrap对象,并不是Bean)
- 判读并标记是否是InstantiationAwareBeanPostProcessor(实例化处理器)
- 判断并标记是否是DestructionAwareBeanPostProcessor(销毁处理器)
- 添加到BeanPostProccessor列表中
- 根据PostProcessorName获取Bean
- 注册没有实现优先级接口的BeanPostProccessor
- 实例化剩下的非lazy-init单例(finishBeanFactoryInitialization->preInstantiateSingletons)
- 获取容器中全部的Bean名称
- 判断是否是FactoryBean,
- 如果不是FactoryBean直接获取创建Bean对象(getBeanName)
- 先检查单例缓存中是否存在手动注册的单例,(第一次创建单例,返回都是null)
- 创建bean实例
- 给BeanPostProcessors返回一个代理对象替代目标bean实例的机会
- 如果是InstantiationAwareBeanPostProcessor,就执行applyBeanPostProcessorsBeforeInstantiation。
- 然后调用doCreateBean()进行真实Bean的创建。
- 给BeanPostProcessors返回一个代理对象替代目标bean实例的机会
增强Calculator bean的流程
在refresh()->finishBeanFactoryInitialization中完成
- 实例化剩余的非懒加载的单例
- 获取全部的beanNames,循环遍历
- 获取bean定义(getBean(calculator))
- 先尝试从缓存中获取bean(第一次获取,为null)
- 标记bean已经被创建
- 获取bean依赖的bean并先进行创建(这里为null)
- 创建bean实例->createBean(beanName, mbd, args)
- 给BeanPostProcessors尝试返回代理对象的机会(resolveBeforeInstantiation)
- 进入Instantiation前置方法,执行前置处理器
- 获取全部的处理器,循环遍历,如果为InstantiationAwareBeanPostProcessor则调用前置处理器方法
- 当执行到AnnotationAwareAspectJAutoProxyCreator,执行器前置方法:
- 如果有自己定义的TargetSource则创建一个代理,这里为null(并没有起到实际的作用)
- 进入Instantiation前置方法,执行前置处理器
- doCreateBean()创建bean实例
- createBeanInstance()使用工厂方法(instantiateUsingFactoryMethod)调用Calculator构造方法,进行初始化构造
- 创建一个BeanWrapperImpl实现类
- 初始化BeanWrapperImpl(此时只包含默认值)
- 获取FactoryBeanName:cap10MainConfig
- 获取factoryBean:cap10MainConfig(被加强的)
- 当不使用任何factoryMethod和参数,尝试所有匹配给定参数的方法
- 获取全部符合条件方法(匹配到calculator())
- 如果只有一个符合条件的方法,将calculator()存入mdb.resolvedConstructorOrFactoryMethod
- instantiate()实例化bw bean装饰类
- 使用CGLIB的instantiate进行实例化
- 调用invoke()->intercept:cglibMethodProxy.invokeSuper->...->Calculator()构造函数
- 允许后置处理器修改合并的bean定义:applyMergedBeanDefinitionPostProcessors()
- 如果是MergedBeanDefinitionPostProcessor则执行其postProcessMergedBeanDefinition()
- populateBean给bean实例赋值
- 在配置属性前给InstantiationAwareBeanPostProcessors修改bean的机会,通过postProcessAfterInstantiation方法
- 检查如果实现了InstantiationAwareBeanPostProcessor,通过postProcessProperties获取PropertyValues
- applyPropertyValues应用属性值
- initializeBean():执行Bean初始化方法
- 调用Aware方法:invokeAwareMethods()(这里不存在Aware方法直接跳过)
- 调用Initialization前置处理器:applyBeanPostProcessorsBeforeInitialization()
- 获取全部的BeanPostProcessors,循环调用postProcessBeforeInitialization()--这里没做具体操作
- 调用初始化方法
- 判断bean类型是否是InitializingBean(这里跳过)
- 获取初始化方法
- 调用Initialization后置处理器
- 获取全部的BeanPostProces,循环遍历执行postProcessAfterInitialization()
- 如果需要,包装给定的bean,例如,当需要被代理。eg:当遇到AnnotationAwareAspectJAutoProxyCreator时,执行wrapIfNecessary():返回一个代理对象
- 创建代理
- 获取全部的拦截器
- 创建Proxy:
- 构建增强器advisors
- 添加到ProxyFactory
- 创建Proxy(getProxy()->createAopProxy().getProxy()) 这里返回一个cglibaop代理
- 创建代理
- 经过上一阶段的处理,返回的wrappedBean实际上变成了增强过后的代理对象,最终向上传递最后实际创建的是一个增强的代理对象。
- createBeanInstance()使用工厂方法(instantiateUsingFactoryMethod)调用Calculator构造方法,进行初始化构造
AOP的调用流程
div(4, 1)入口:
- 进入拦截intercept()方法
- 获取TargetSource(包含Calculator)
- 获取目标类,target=targetSource.getTarget()
- 获取目标类对象类型
- 获取拦截链 getInterceptorsAndDynamicInterceptionAdvice()
- 尝试从缓存中获取方法列表
- 如果没有,则从advisorChainFactory中获取(getInterceptorsAndDynamicInterceptionAdvice())
- 获取advisors列表,并创建interceptorList
- 循环遍历advisors,如果类型为PointCutAdvisor进行处理:(如果匹配为真,则添加到interceptorsList中)
- 由advice获取拦截方法列表
- 添加到interceptorList列表中
- 添加到methodCache中
- 如果没有拦截器链直接执行目标方法
- 如果有,创建一个方法调用(CglibMethodInvocation(..).proceed())
- 链式获取每一个拦截器,执行每一个拦截器的invoke方法,该拦截器等待下一个拦截器返回以后再执行。
小结
@EnableAspectJAutoProxy
开启AOP功能:主要在容器中注入了一个组件AnnotationAwareAspectJAutoProxyCreator对象
简述流程
- registerBeanPostProcessors():注册后置处理器-其中创建了AnnotationAwareApectJAutoProxyCreator对象
- finishBeanFactoryInitialization():初始化剩余的单实例bean
- 创建业务逻辑和切面组件
- AnnotationAwareAspectJAutoProxyCreator:拦截组件的创建过程
- 判断组件是否需要增强,如果需要增强,返回一个代理对象
- 执行目标方法
- 代理对象执行目标方法
- CglibAopProxy.intercept()拦截
- 获取一个拦截链
- 利用链式拦截器,依次执行拦截器内方法
- 执行顺序:
- 正常:前置->目标方法->后置->返回通知
- 异常:前置->目标方法->后置->异常通知
Spring AOP部分源码分析的更多相关文章
- Spring AOP高级——源码实现(1)动态代理技术
在正式进入Spring AOP的源码实现前,我们需要准备一定的基础也就是面向切面编程的核心——动态代理. 动态代理实际上也是一种结构型的设计模式,JDK中已经为我们准备好了这种设计模式,不过这种JDK ...
- Spring IOC 容器源码分析 - 余下的初始化工作
1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...
- Spring IOC 容器源码分析 - 填充属性到 bean 原始对象
1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...
- Spring IOC 容器源码分析 - 循环依赖的解决办法
1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...
- Spring IOC 容器源码分析 - 创建原始 bean 对象
1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续.在上一篇文章中,我们从战略层面上领略了doCreateBean方法的全过程.本篇文章,我们就从战术的层面上,详细分析doCreat ...
- Spring IOC 容器源码分析 - 创建单例 bean 的过程
1. 简介 在上一篇文章中,我比较详细的分析了获取 bean 的方法,也就是getBean(String)的实现逻辑.对于已实例化好的单例 bean,getBean(String) 方法并不会再一次去 ...
- Spring IOC 容器源码分析 - 获取单例 bean
1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...
- Spring IOC 容器源码分析系列文章导读
1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...
- 九、Spring之BeanFactory源码分析(一)
Spring之BeanFactory源码分析(一) 注意:该随笔内容完全引自https://blog.csdn.net/u014634338/article/details/82865644,写的 ...
随机推荐
- 1054. [HAOI2008]移动玩具【BFS】
Description 在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动 时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移 ...
- yii在哪些情况下可以加载yiilite.php?
yii权威指南上说,在开启apc缓存的情况下,可以加载yiilite.php提升性能.我有以下几点疑问: 1.开启apc缓存的情况下,引入yiilite.php能提升性能的原因是因为缓存了opcode ...
- openstack排除查找错误的两种方法
1.openstack日志一般放在什么什么位置?2.如何调试openstack命令执行过程? 我们会经常错误,但是我们碰到错误该怎么做,该如何找到原因.对于openstack有两种办法:在上一篇文章h ...
- ES6新特性1:let和const
本文摘自ECMAScript6入门,转载请注明出处. 一.let 1. ES6增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. { let a ...
- python基础整理7——爬虫——爬虫开发工具
HTTP代理神器Fiddler Fiddler是一款强大Web调试工具,它能记录所有客户端和服务器的HTTP请求. Fiddler启动的时候,默认IE的代理设为了127.0.0.1:8888,而其他浏 ...
- 列表中不限制宽度,hover时,字体font-weight:bold,防止抖动
项目一个小问题困扰了很久,在一个没有限制宽度的列表容器中,如果给hover时,给字体➕'font-wieght:bold'容器就会变宽,然后移动的下一个容器,就会出现抖动,这样很是影响用户体验,于是在 ...
- $Mayan$游戏
\(Mayan\)游戏 好啊,一年(半年)来的梦魇,终于结束了. 其实我从来没料到整体竟然会如此暴力--做的时候机房里冷得很,感觉晕晕乎乎地做完了,晕晕乎乎地调了好久,晕晕乎乎地听(看了题解的)\(q ...
- 流程一直处于Running状态,应该怎么停止?
流程一直处于Running状态,应该怎么停止? 概述 我们有遇到这种情况:可能由于某些原因,流程发起后一直处于Running状态,然后我们想Stop掉这些出问题的流程,这个时候你在Workspace里 ...
- GoogleTest初探(1)
此篇主要了解一下GoogleTest中的断言. 总的来说,GoogleTest中的断言分为两大类:EXPECT_*和ASSERT_*,这两者在测试成功或失败后均会给出测试报告,区别是前者在测试失败后会 ...
- 【数据结构与算法】001—栈与队列(Python)
栈与队列 1.栈(stacks)是一种只能通过访问其一端来实现数据存储与检索的线性数据结构,具有后进先出(last in first out,LIFO)的特征 2.队列(queue)是一种具有先进先出 ...