IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring源码分析(一) -> 正文阅读

[Java知识库]Spring源码分析(一)

Spring源码分析(一)

前言

? 本人在研究生时期的项目一直是使用的C++,到毕设时导师给定的课题需要用Java实现,所以当时简单的学了SSM框架。当时也仅限于知道Spring的简单的使用,找工作用的也是C/C++,可是入职后三个月为了适应公司的需求,“自愿”转了java,由于有研究生时候的经验,所以相比于其他转java的同事,我情况可能还是比较好的。

? 转java后也用的都是公司现成的框架,项目都是现成的,骨架都早已搭好,只需会基本的if-else,再加上照着之前的代码框架写就行了,一直也没时间(其实就是沉醉在刚入职的新鲜感中,没有想着去看,疏忽了个人的成长)去好好看看Spring,spring的水平也一直停留在毕设时简单使用的水平,也没有对Spring有太多重视。到现在两年了,考虑换公司,发现我一个搞java 的连Spring的源码都没看过,有点说不过去,于是开始找资料了解Spring源码(所以跳槽让人技术成长)。

? 本人看的是从同事那里分享的《子路》讲的源码系列,本博客的目的有三个:

  1. 通过写博客,巩固自己看视频所得。
  2. 做记录,以便自己之后翻看,回顾。
  3. 可以发表出来让网友进行观看,以便于发现自己写的是否有问题。

好了,废话不多说,开始吧。

准备工作

IDE运行spring源码。(我的是5.0.x)

Spring环境初始化流程(一)

Spring环境的初始化,在没有SpringMVC的情况下,通过在main方法中创建ApplicationContext来初始化Spring环境。鉴于springboot的兴起,注解方式逐渐取代了XML的方式(其实就是人家子路讲的就是这个·······),所以使用 AnnotationConfigApplicationContext 来初始化spring环境。

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

通过上述代码就创建好了一个spring环境,接下里就可以使用applicationContext调用getBean方法获取bean实例了。通过点进去上面一行代码可以看到它主要做了四个动作:

this();
register(annotatedClasses);
refresh();

明明只有三个语句,为什么是四个动作?因为在调用this()无参构造方法时肯定会先构造父类,所以还隐含着有一个父类的构造方法。

1. 父类构造方法
// GenericApplicationContext.java

public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

可以看到,在父类构造方法中,就干了一件事:进行beanFactory的初始化。(当然了,在DefaultListableBeanFactory 的构造方法中也进行了一些设置,这这些我们前期可以忽略,不会对主流程产生影响)

BeanFactory:构建Bean的工厂,spring环境中最重要的组件,它里面包含了生成bean所需要的原料(BeanDefinitionMap)和工具(比如各种后置处理器),以及存放bean实例的容器(singletonObjects)。

BeanDefinitionMap:bean工厂重要容器,存放<beanNAME, beanDefinition>对。(下文简称BDMap

Beandefinition:Bean的定义,一个BeanDefinition描述了一个bean的各种属性,比如是否单例、是否懒加载,它的class,根据bd来生成bean实例

2. this(), 即AnnotationConfigApplicationContext()

AnnotationConfigApplicationContext 的无参构造方法中,完成了两件事儿,初始化两个组件:reader和scanner,其中第一件很重要。

//AnnotationConfigApplicationContext.java

// 可以看到参数传的是this,即整个环境上下文,而参数类型要求是registry,通过查看代码,发现果然GenericApplicationContext实现了BeanDefinitionRegistry接口
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
1) AnnotatedBeanDefinitionReader

通过点进构造方法进一步跟踪代码,很容易定位到以下代码:

// AnnotationConfigUtils.java
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source){
    // 省略
}

这个方法可以看到分别判断BDMap中是否含有以下七个name的BD

org.springframework.context.annotation.internalConfigurationAnnotationProcessor->ConfigurationClassPostProcessor.class
org.springframework.context.annotation.internalAutowiredAnnotationProcessor->AutowiredAnnotationBeanPostProcessor.class
org.springframework.context.annotation.internalRequiredAnnotationProcessor->RequiredAnnotationBeanPostProcessor.class
org.springframework.context.annotation.internalCommonAnnotationProcessor->CommonAnnotationBeanPostProcessor.class
# org.springframework.context.annotation.internalPersistenceAnnotationProcessor->PersistenceAnnotationBeanPostProcessor.class
org.springframework.context.event.internalEventListenerProcessor->EventListenerMethodProcessor.class
org.springframework.context.event.internalEventListenerFactory->DefaultEventListenerFactory.class

如果不包含(这里是初始化,肯定不包含),则将以上七个name对应的class生成BD,然后调用以下方法:

// AnnotationConfigUtils.java
private static BeanDefinitionHolder registerPostProcessor(
			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName){}
// DefaultListableBeanFactory.java
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition){
    //...
    this.beanDefinitionMap.put(beanName, beanDefinition);
    this.beanDefinitionNames.add(beanName);
    this.manualSingletonNames.remove(beanName);
}

registerBeanDefinition方法完成beanDefinition的注册,即将以上六个BD放入BeanFactory中的BDMap中,(PersistenceAnnotationBeanPostProcessor比较特殊不做讨论).

这里可以看到:

  1. 把A类转换成BD的方法:XXXBeanDefinition bd = new XXXbeanDefinition(A.class);

    XXXBeanDefinition表示Spring内部有多种BeanDefinition类型,这里用的是RootBeanDefinition,表示是spring内部的,还有AnnotatedBeandefinition等

  2. AnnotatedBeanDefinitionReader的作用:BD读取器。

本步骤完成了spring内部六个BD 的注册;

2) ClassPathBeanDefinitionScanner

“可以” 用来扫描包或者类,继而转成BD;
但是实际上环境初始化扫描包的工作不是scanner对象来完成的;
而是在refresh时调用的invokeBeanFactoryPostProcessors方法中new了一个ClassPathBeanDefinitionScaaner来完成包扫描的;
这里的scanner仅仅是为了程序员能够在外部调用AnnotationApplicationContext中的scan方法;

也就是说在spring自动初始化过程中用不到这个scanner

3. register(annotatedClasses)

这里的annotatedClasses一般都会是一个配置类(即带@Configuration和@ComponentScan注解的类)。

这个方法完成的事情是:将配置类注册到BDMap中,第一个用户类,Spring无法自动获取,需要用户手动注册,之后的其他类则可以通过ComponentScan实现自动扫描。

总结

以上三步大致总结如下:

  1. 初始化默认BeanFactory
  2. 注册六个spring内部的BD(这几个BD都是spring内部的后置处理器,属于spring的扩展点,用户自己也可以参照这几个类开发自己的类,介入spring的流程)
  3. 注册用户配置类

以上三步完成了初始化spring环境进行初始化的准备工作。第四步refresh() 是重头戏!会完成工厂的初始化和bean的实例化。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 14:00:25  更:2021-07-22 14:04:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/18 18:20:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码