当前位置:

首页 > 编程开发 > java中Spring源码分析

java中Spring源码分析

源码分析1.前期准备/***springdebug*@authorhuangfu*/publicclassSpringDebug{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextapp=newAnnotationConfigApplicationContext(SpringDebugConfig.class);}}上面这一行代码我估计使用过Spring的人都特别熟悉,如果不熟悉,那我劝你先学会使用,再去深究一些源码的

本文目录

    源码分析

    1.前期准备

    /**
    * spring debug
    * @author huangfu
    */
    public class SpringDebug {
    public static void main(String[] args) {
    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringDebugConfig.class);
    }
    }
         

    上面这一行代码我估计使用过Spring的人都特别熟悉,如果不熟悉,那我劝你先学会使用,再去深究一些源码的底层逻辑!

    下面我们看一下,他究竟是如何一步一步的实例化bean,接管bean,然后执行各种生命周期类的!我们先不妨猜测一下,spring再读取这些bean的时候,关于bean的信息一定是存放在了某一个实体上,那么这个实体是什么呢?这个类就是BeanDefinition那么他存储了什么东西呢?我们看一下它的子类AbstractBeanDefinition

    java中Spring源码分析        

    里面定义这类似与这样的属性值,当然作者做截取了少数属性,它里面的属性远远比这多得多,它的目的就是bean实例化的时候,需要的数据不需要再通过自己去反射获取,而是再Spring初始化的时候全部读取,需要的时候从这里面拿就行,了解了bd的概念之后,我们是否疑惑?他读取之后存放在哪里呢?答案是存放再beanFactory里面,所以Spring初始化的时候肯定会先实现一个bean工厂!进入到AnnotationConfigApplicationContext里面,你会发下并没有初始化,在那初始化呢?众所周知,一个类再初始化的时候会先加载父类的构造函数,所以我们需要去看一下它的父类GenericApplicationContext:

    public GenericApplicationContext() {
       //初始化bean的工厂
       this.beanFactory = new DefaultListableBeanFactory();
    }
         

    果然不出我所料,它再父类里面创建了bean工厂,工厂有了,我们继续回到AnnotationConfigApplicationContext里面往下看:发现它调用了一个this(),说明它调用了自己的空构造方法,所以,我们进入看一下:

    public AnnotationConfigApplicationContext() {
       //初始化读取器
       this.reader = new AnnotatedBeanDefinitionReader(this);
       //初始化扫描器
       this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
       

    「至此我们就可以看对照上面那幅图:初始化的时候bean工厂有了」

    java中Spring源码分析        

    「然后再自己的空构造方法里面有初始化了读取器!」

    java中Spring源码分析        

    那我们继续回到AnnotationConfigApplicationContext构造方法里面:

       /**
    * 创建一个新的AnnotationConfigApplicationContext,从给定的带注释的类派生bean定义
    * 并自动刷新上下文。
    * @param annotatedClasses one or more annotated classes,
    * e.g. {@link Configuration @Configuration} classes
    */
    public AnnotationConfigApplicationContext(Class... annotatedClasses) {
    //读取Spring内置的几个的class文件转换为bd  然后初始化bean工厂
    this();
    //这一步就是将配置类Config进行了注册并解析bd
    register(annotatedClasses);
    //这一步是核心,Spring的理解全在这一步,这一步理解了也就可以说将Spring理解了70%
    //内部做一系列的操作如调用bean工厂的后置处理器   实例化类  调用 后置处理器的前置处理   初始化类  调用后置处理器的后置处理 注册事件监听等操作
    //完成一个类从class文件变为bean的生命周期
    refresh();
    }
         

    下一步是调用register方法,干什么呢?试想一下,有时候我们的自动扫描配置是通过注解@ComponentScan("com.service")来配置的,这个类一般在哪?对了,一般实在配置类中的!

    @Configuration
    @ComponentScan("com.service")
    public class SpringDebugConfig {}
         

    为了能够知道,我们要扫描那些包下的类,我们就必须先去解析配置类的BeanDefinition,这样才能获取后续咱们要解析的包,当然这个方法不光解析了扫描的包,还解析了其他东西,本文不做讲解!     

    2.核心功能

    好了,再往下走我们就知道了我们即将要扫描那些包下的类,让他变成bean,那么我们继续向下走,走到refresh();这个方法不得了他是整个Springbean初始化的核心方法,了解了它也就能够了解Spring的实例化,回调等一些列的问题,我们进去看看:

    进来之后,我们一个方法一个方法的分析做了什么功能,首先是:     

    1). prepareRefresh();
    ❝      

    这里是做刷新bean工厂前的一系列赋值操作,主要是为前面创建的Spring工厂很多的属性都是空的,这个方式是为他做一些列的初始化值的操作!

    ❞             
    2). obtainFreshBeanFactory()
    ❝      

    告诉子类刷新内部bean工厂  检测bean工厂是否存在 判断当前的bean工厂是否只刷新过一次,多次报错,返回当前使用的bean工厂,当该步骤为xml时 会新建一个新的工厂并返回

    ❞             
    3). prepareBeanFactory(beanFactory);
    ❝      

    这里是初始化Spring的bean容器,向beanFactory内部注册一些自己本身内置的Bean后置处理器也就是通常说的BeanPostProcessor,这个方法其实也是再初始化工厂!

    ❞             
    4). postProcessBeanFactory(beanFactory);
    ❝      

    允许在上下文子类中对bean工厂进行后处理,作用是在BeanFactory准备工作完成后做一些定制化的处理! 但是注意,你点进去是空方法,空方法以为着什么?意味着Spring的开发者希望调用者自定义扩展时使用!

    ❞             
    5). invokeBeanFactoryPostProcessors(beanFactory);
    ❝      

    其实相信看名字,大部分读者都能够猜出,他的目的是扫描非配置类的bd注册到工厂里面,扫描完成之后,开始执行所有的BeanFactoryPostProcessors,这里出现了第一个扩展点,自定义实现BeanFactoryPostProcessors的时候,他的回调时机是在Spring读取了全部的BeanDefinition之后调用的,具体的使用方法读者自行百度!

    ❞             
    6). registerBeanPostProcessors(beanFactory);
    ❝      

    这里是注册bean的后置处理器 也就是  beanPostProcessor 的实现 还有自己内置的处理器  注意这里并没有调用该处理器,只是将胡处理器注册进来bean工厂! 不知道大家使用过beanPostProcessor接口这个扩展点吗?他就是再这个方法里面被注册到Spring工厂里面的,当然注意一下,他只是注册进去了,并没有执行!记住并没有执行!

    ❞            
    7). initMessageSource();
    ❝      

    怎么说呢,这个方法作者并不准备深究,因为他和本篇文章的意图相违背,他的目的是做一个国际化操作也就是 i18n的资源初始化

    ❞             
    8).initApplicationEventMulticaster();
    ❝      

    Spring为我们提供了对于事件编程的封装,一般来说事件分为三个角色,事件广播器(发布事件),事件监听器(监听事件),事件源(具体的事件信息)三个角色,这个方法的目的就是初始化事件的广播器!

    ❞             
    9). onRefresh();
    ❝      

    这里又是一个扩展点,内部的方法为空,Spring并没有实现它,供调用者实现!

    ❞             
    10). registerListeners();
    ❝      

    注册Spring的事件监听器,上面已经说过了,这里是初始化并且注册事件监听器

    ❞             
    11). finishBeanFactoryInitialization(beanFactory);
    ❝      

    这个方法是一个重点,他是为了实例化所有剩余的(非延迟初始化)单例。我们所说的bean的实例化,注入,解决循环依赖,回调beanPostProcessor等操作都是再这里实现的!

    ❞        
    12). finishRefresh();
    ❝      

    最后一步:发布相应的事件。Spring内置的事件

    ❞        

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    Java单元测试入门:使用JUnit 5编写第一个测试用例
    Java单元测试入门:使用JUnit 5编写第一个测试用例

    面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

    Java变量未初始化报错解析:局部变量与成员变量默认值差异
    Java变量未初始化报错解析:局部变量与成员变量默认值差异

    深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

    详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

    Java中final与static final常量的定义及初始化规则
    Java中final与static final常量的定义及初始化规则

    深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

    Java抽象方法与接口方法的区别及选型建议
    Java抽象方法与接口方法的区别及选型建议

    深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

    Java实现HTTP请求与JSON解析的完整代码示例
    Java实现HTTP请求与JSON解析的完整代码示例

    本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

    Java递归出现StackOverflowError的原因分析及栈空间优化方案
    Java递归出现StackOverflowError的原因分析及栈空间优化方案

    详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

    Java空指针异常(NPE)的代码排查与修复实例
    Java空指针异常(NPE)的代码排查与修复实例

    针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。