2023-07-16
源码分析
0

目录

开篇
总结

学习源码之前先思考一个问题,我们为什么要学习源码?有什么用?

工作这么多年我总结了以下几点原因

  • 第一点:应付面试!现在Java开发人员越来越多,公司的要求也变得越来越高,源码成为我们必不可少的面点!
  • 第二点:核心竞争!现在氛围好点的公司中,大家工作中对技术讨论还是比较多的,如果你不懂源码的话就没办法参与到源码这部分的讨论中,更不用说参与一些核心代码的开发工作
  • 第三点:学以致用!之前部署一套新Cloud服务的时候,同事遇到Feign调用其他服务报 ClientException 异常的问题,在大家轮番上场都一筹莫展的时候,我运用学习源码时的思路,逐步分析Ribbon源码,最终解决了问题
  • 第四点:组件封装!学会源码以后,就可以根据源码扩展出各种组件,是高级开发必备技能

开篇

我在学习Spring源码的过程中略有心得,通过流程图记录下源码执行流程、各种扩展点以及一些自己的理解。

image.png

  • Spring在启动时会先创建 BeanFactory,默认是ConfigurableListableBeanFactory,
  • 通过BeanDefinitionReader解析xml、注解等定义的Bean信息包装成BeanDefinition存到BeanFactory中的BeanDefinitionMap中,
  • 然后调用BeanFactoryPostProcessor接口进行扩展,
  • 进行实例化前的准备工作:注册BeanPostProcesser、初始化国际化资源、初始化事件多播器、注册监听器。
  • 准备完成后对所有非延迟加载的单例进行实例化,通过反射的形式创建对象,进行属性填充,然后进行相应的Aware接口的感知调用,
  • 执行BeanPostProcesser的前置处理,在初始化方法调用之后执行BeanPostProcesser的后置处理,
  • 此时Bean的对象创建完成

源码的学习,都是从上面的流程学起,面试经常问题的Spring Bean的生命周期,就是上面图中,Bean创建的流程,在BeanFactory中有对应的注释,如下:

image.png

在源码中 AbstractApplicationContext #refresh 方法即为Spring Bean完整生命周期的体现

java
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); contextRefresh.end(); } } }

总结

想要掌握Spring源码应该先掌握Spring的生命周期(Bean信息是怎么加载、解析、实例化、初始化、使用、销毁的),脑海中有一个框架轮廓,知道Spring先做了什么,后做了什么,有一个大概了解。

脑海中有了Spring的轮廓之后,开始思考细节,例如:Bean信息是怎么加载的?加载的Bean信息是直接生成可用的Bean吗?每一步流程都动脑思考扩展点,怎么应用到业务中,这个扩展适合哪些业务场景等。

在看源码的过程中,要学会关联思考,源码中往往是初始化数据后,n个方法后会用到的。

最后一点,学过源码后一定要思考、做笔记,回头来看学过的知识点能在脑海中立马回忆起来,争取做到对源码为所欲为的境界!!!

本文作者:柳始恭

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!