Spring 的源码分析 2022-01-13 程序之旅,记录 2 条评论 1194 次阅读 ## Spring 的源码分析 [TOC] 本次分析的目的是: - Spring IoC 源码的分析 - Spring AOP 源码的分析 分析前先搞清楚两个概念 - IOC/DI:控制反转/依赖注入,是一种技术思想,不是一个技术实现。IoC解决对象之间的耦合问题。 - AOP: ⾯向切⾯编程/⾯向⽅⾯编程,在不改变原有业务逻辑情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。 **分析构建环境** - 源码地址:https://github.com/spring-projects/spring-framework/releases - Idea 2018 - gradle 5.6.3 [安装方法](https://blog.csdn.net/chuanchengdabing/article/details/115309250) ### Spring IoC 源码的分析 #### Spring IoC 的初始化流程 > ApplicationContext 具体实现有 ClassPathXmlApplicationContext 和 AnnotationConfifigApplicationContext, ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容,AnnotationConfifigApplicationContext 则是包含了注解解析等⼀系列的内容。这里以 ClasspathXmlApplicationContext 为例,深入源码说明 IoC 容器的初始化过程。 ##### Bean 生命周期的关键时机点 创建一个 TraceBean,然后实现几个特殊的接口,并分别分析接口实现的构造器、接口方法中断点,分析出 Bean 对象创建和管理关键点的触发时机。 ``` TraceBean implements InitializingBean (接口实现 afterPropertiesSet) MyBeanPostProcessor implements BeanPostProcessor (接口实现 postProcessBeforeInitialization、postProcessAfterInitialization) MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor (接口实现 postProcessBeanFactory) ``` 测试启动断点,分析得出以下的结论: - **TraceBean** 分析 - **TraceBean** 的构造器调用时机是在 **AbstractApplicationContext** 类中的 **refresh** 方法中的 **finishBeanFactoryInitialization**(beanFactory) 处。 - **InitializingBean** 的接口方法 **afterPropertiesSet**(也是 TraceBean 的接口方法),调用时机也是在 **AbstractApplicationContext** 类中的 **refresh** 方法中的 **finishBeanFactoryInitialization**(beanFactory) 处。 - **MyBeanFactoryPostProcessor** 分析 - **MyBeanFactoryPostProcessor** 构造函数在 **AbstractApplicationContext** 类 **refresh** ⽅法的 **invokeBeanFactoryPostProcessors**(beanFactory) 触发。 - **MyBeanFactoryPostProcessor** 的 **postProcessBeanFactory** 方法在 **AbstractApplicationContext** 类 **refresh** ⽅法的 **invokeBeanFactoryPostProcessors**(beanFactory) 触发。 - **MyBeanPostProcessor** 分析 - **BeanPostProcessor 初始化**在 **AbstractApplicationContext** 类 **refresh** ⽅法的 **registerBeanPostProcessors**(beanFactory)。 - **postProcessBeforeInitialization** 调⽤在 **AbstractApplicationContext** 类 **refresh** ⽅法的**finishBeanFactoryInitialization**(beanFactory)。 - **postProcessAfterInitialization** 调⽤在 **AbstractApplicationContext** 类 **refresh** ⽅法的**finishBeanFactoryInitialization**(beanFactory)。 ##### Bean 生命周期执行流程 1. 构造函数:根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。 2. 依赖注入:利用依赖注入完成 Bean 中所有属性值的配置注入 3. BeanNameAware:如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。 4. BeanFactoryAware:如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFacotry() 方法传入当前工厂实例的应用。 5. ApplicationContextAware:如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前的 ApplicationContext 实例的引用 6. BeanPostProcessort 前置方法:如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法。postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的 7. InitializingBean:如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方 8. 自定义 init 方法:如果在配置文件中通过 init-method 属性指定了初始化方法,则调用改初始化 9. BeanPostProcessor 后置方法:如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法postProcessAfterInitialization()。此时,Bean 已尽可以被应用系统使用了。 10. 使用:如果在 \ 中指定了改 Bean 的作用范围为 scope="singleton",则将该 Bean 放入 Spring Ioc 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 \ 中指定改 Bean 的作用范围为 scope="prototype",则将该 Bean交给调用者。 11. DisposableBean:如果 Bean 实现了 DisposableBean 接口,则 Spring 回调用 destory() 方法将 Spring 中的 Bean 摧毁;如果在配置文件中 通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。 可以参考简单的流程图 ![bean 生命周期](https://mufeng-blog.oss-cn-beijing.aliyuncs.com/typecho/bean%20%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png) ##### Spring IoC 容器初始化主流程 由上可知,Sping IoC 的初始化过程中,最主要的是 AbstractApplicationContext#refresh() 方法。可以分析 refresh 方法来进行讨论。 1. prepareRefresh() 容器刷新之前的准备工作 2. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 获取一个刷新过后的 beanFactory,默认实现是 DefaultListableBeanFactory,加载 BeanDefition 并注册到 BeanDefitionRegistry 3. prepareBeanFactory(beanFactory) beanFactory 的标准初始化工作 4. **postProcessBeanFactory**(beanFactory) BeanFactory准备⼯作完成后进⾏的后置处理⼯作 5. **invokeBeanFactoryPostProcessors**(beanFactory) 实例化并调⽤实现了 BeanFactoryPostProcessor 接⼝的 Bean。(也就是上边我们自定义的 MyBeanFactoryPostProcessor) - ConfigurationClassPostProcessor - ConfigurationClassParser - ClassPathBeanDefinitionScanner 6. **registerBeanPostProcessors**(beanFactory) 给 factory 注册 Bean 后置处理器,在创建 bean 的前后执行。(也就是上边我们自定义的 MyBeanPostProcessor) 7. initMessageSource() 初始化 messageSource 组件,用于解析国际化文件:消息绑定,消息解析 8. initApplicationEventMulticaster(); 初始化事件派发器 9. onRefresh(); 给子类的扩展接口,通常没做任何事,在容器刷新的时候可以自定义逻辑。 10. registerListeners(); 注册 ApplicationListener 接口的监听器 11. finishBeanFactoryInitialization(beanFactory); 初始化所有剩下的非懒加载的单例 bean,初始化创建非懒加载方式的单例 Bean 实例(未设置属性)。 12. finishRefresh(); 完成 context 的刷新。主要调用LifecycleProcessor的onRefresh()⽅法,并且发布事件(ContextRefreshedEvent) #### Spring IoC 循环依赖问题 循环依赖就是循环引用,两个或者两个以上的 Bean 相互持有对方,形成环。Spring 中循环依赖的场景有: - 构造器的循环依赖(不能解决) - 单例 Field 属性的循环依赖 (能解决) - 多例 Field 属性的循环依赖 (不能解决) 其中,构造器的循环依赖无法解决,值能跑出 BeanCurrentlyInCreationException 异常,在解决属性循环依赖时,spring 采用的是提前暴露对象的方法。非抽象、单例 并且非懒加载的类才能被提前初始 Bean ,通过 setXXX 或者 @Autowired 来解决循环依赖。 spring 主要是通过三级缓存来解决循环依赖的问题: - singletonObjects: 一级缓存,用于保存实例化、注入、初始化完成的bean实例 - earlySingletonObjects:二级缓存,用于保存实例化完成的bean实例 - singletonFactories:三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。 下图告诉循环依赖的解决流程 ![spring 循环依赖](https://mufeng-blog.oss-cn-beijing.aliyuncs.com/typecho/spring%20%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96.png) ### Spring AOP 源码分析 > 主要是探究 Spring AOP 的创建时机 AOP源码分析类⽅法调⽤关系过程中记录 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean() 调⽤ org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization (循环执行处理后置处理器) 调⽤org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization(后置处理器AbstractAutoProxyCreator完成bean代理对象创建) 调⽤ **org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary**(创建代理对象) 调⽤ org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy(在这⼀步把委托对象的aop 增强和通⽤拦截进⾏合并,最终给代理对象) 调⽤ org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy 调⽤ org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader) 打赏: 微信, 支付宝 标签: spring, 源码 本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
学到了
大佬牛批