Spring 源码解析

spring 源码解析(1) 初始加载

前言

我很喜欢一句话,年轻时候多学一分,以后就少求别人一次,也送给看博客的各位,下面开始正题

IOC

先谈谈什么是IOC?
  讲真的,这个问题有点老生常谈了,IOC根据官方的语义就是: 控制反转(Inverse Of Control),在
  拆分的细致一点: 这个控制指的是什么?反转又是什么意思?

再次之前我们先来回想一个问题: 不涉及到框架本身我们创建一个对象的方法有哪些?

1. new ClassName(); ---> 直接new对象的方式
2. class.forName(); ---> 通过反射去生成一个对象

这俩只说了两种类型,但是你要思考一个问题: 一个网站的访问有成百上千个人,按照正常逻辑的话,
我们是在我们需要的时候去生成这个对象,采取的方式可能是1也可能是2,注意这里面的关键词! 当我们需要的时候!!!
说的很清楚了,是当我们需要的时候再去创建,创建与否在于我们需要或者不需要!

而IOC呢?控制的是什么?反转的又是什么?通俗来讲控制的是对象,反转的是控制权,也就是说对象的生成创建与否
不再是我们所关心的问题,而是由配置文件去决定的,如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="com.foo.entity.Student">
        <property name="name" value="zhangsan"/>
        <property name="age" value="20"/>
     </bean>

</beans>

我们只需要将对象配置在文件中即可

IOC反转是如何生成对象的

这个问题,在第一篇spring的博文里面提出来有点早了,因为这里面的内容涉及的非常多非常多!简单说一点:
将对象交给spring“容器”来处理,它是怎么样子把对象存储供后续使用的?初始化的方式有哪些?
第一次使用和第二次使用有什么差别?。。。很多,这里先把问题引出来,下面我们回归正题:
基于Spring容器对象的创建生成步骤有哪些?

第一步 —> 资源来

不管是基于XML或者注解说白点都是寻找资源的过程,我们这个系列博文全是XML方式的配置,因为道法自然(其实都差不多,后面也会说注解的方式),根据项目来看如下:

在这里插入图片描述

这个是项目的大体配置,我们可以很清楚看到,配置文件applicationContext.xml是在resource这个目录下面的,下面看我们的第一行代码如下:

Resource resource = new ClassPathResource("applicationContext.xml");

乍一眼一看,哦~Resource 这个东西八成是加载资源的,再看看后面的new ClassPathResource("xxxx.xml"),不
出意外应该是加载类路径下的xxx.xml文件了

其实,这里面我是有疑问的: 我自己提出来吧

1、为什么是从Resource这个文件夹下面加载的?
2、加载进去之后以什么样子的形式存在?

这一行代码我们围绕这两个问题去讨论
先去看Resource


在这里插入图片描述

首先从层次体系结构上来说Resource 是 InputStreamResource的一个子类,大体上的翻译就是: 对底层资源比如,文件或者类路径资源的一个描述!我们接着看下ClassPathResource("xxx");,看一下这个类:

在这里插入图片描述

大体意思说的是什么呢?首先这个类把它是Resource的实现类,然后这个类或者这个资源对象要绑定一个
ClassLoader,要么是给的一个类加载器,要么是当前类的(这里面有点判断),主要用于将资源文件解析
为File文件

看到这里我大概明白了,我是个憨批吖!我一直以为这个
Resource resource = new ClassPathResource("applicationContext.xml");
直接把我们的XML解析成流了,到这里才明白主要就是干了俩事
1. 处理下传进来的路径信息
2. 搞到一个类加载器

如下图:
在这里插入图片描述

下面我们接着分析

实话实说,上面的:
Resource resource = new ClassPathResource("applicationContext.xml");
我没懂什么意思~也不知道干啥的,没关系,我们继续分析,因为才疏学浅,一起探究吧!
但可以肯定的是资源文件一定和类加载器有点关系。

我们一般出去面试或者跟别人聊天谈论Spring的时候都说!啊啊啊,这个bean对象呢是从工厂里面搞出来的,
其实这里面有个疑问我也不大清楚- -!那就是Spring在扫描XML文件的时候这个延迟加载和非延迟加载究竟差在
哪里!我知道一个是在使用时候才去加载,另外一个是是在初始化的时候再去加载,"但是,如果遇到了Baen的延迟加
载是直接跳过这个对象么"?这个是我们在这里所提出的问题,又扯远了,接回正题。

就像上面所说的,我们spring会把我们所生成的Bean对象放置到BeanFactory里面(这就是我上面所说的,
如果延迟加载的话,"会不会放置在这个里面?还是说以另外一种方式去放置? 继续保留)

所以,我们需要建立一个工厂,将配置的bean对象放置到里面,这个没毛病吧!
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
接下来,我们大致研究上面这个代码,看名字大概也能猜得出来,一个默认的BeanFacyory对象,简单看一下
再点进去的时候发现了这个:

在这里插入图片描述

在这里插入图片描述

啥东西也没有看不出什么,我们再回到DefaultListBeanFactory看一下它的注释

在这里插入图片描述

说的是什么呢,大概的意思是这样子的:

ConfigurableListableBeanFactoryBeanDefinitionRegistry的默认实现,相对来说比较完善这么一个BeanFacyory,一般的用法是将所有的Bean定义的信息读取到这个里面"这个和BeanDefinitionHolder有什么关系呢?保留疑问",然后再访问bean信息,查询它呢也比较简单,因为它是定义在一个本地的表上,通过名字去查询,然后去操作这些预解析的元数据对象

其实,这里面的信息量还是蛮大的
1、将所有的Bean定义的信息读取到这个里面
2、它是定义在一个本地的表上,通过名字去查询
3、预解析的元数据对象

这三点很值得琢么首先第一点,是否可以认为它是一个承载对象信息的容器?第二点将bean定义的信息放置在
了一个本地表上?currentHashMap?第三点预解析元数据信息,预解析?跟我们前面所猜的的延迟加载有啥关系?
我们的延迟加载是不是信息已经被扫到了这个DefaultListBeanFactory里面了呢?只不过并没有放置到
本地的table上面呢?这上面只不过是我的猜测,具体的需要看代码里面是怎么写的

通过上面的分析,我们可以知道,这个DefaultListBeanFactory就是一个放bean定义信息的容器,那么问题来了?数据怎么来?谁放进来的?那么就不得不看下面这行代码了!

BeanDefinitionReader resourceReader = new XmlBeanDefinitionReader(factory);

在这里插入图片描述

解释下: 对传进来的beanFactory创建一个beanDefinitionReader,这个beanFactory里面是一些bean definition信息以 BeanDefinitionRegistry这种形式

在这里插入图片描述

大体的意思是: 为传进的beanFactory生成一个与之匹配的beanDefinitionReader…,我们所关注的点是代码的本身三个对象

  • registry
  • resourceLoader
  • environment

具体的不细展开去说,后面会进行补充

我们上面主要做了这几件事:

1、 定位资源
2、 定义装载beanDefition定义的DefaultListBeanFactory工厂
3、 为DefaultListBeanFactory定义一个与之相关联的definitionReader

仔细想,有没有什么蹊跷的?为什么要绕这么多弯子去加载呢!!!?

根据上面下面我们不难推断,我们要用beanDefinitionReader去读取resource(),将读取到的beanDefinition信息
放置到defaultListBeanFactory里面,那么如下代码应运而生

resourceReader.loadBeanDefinitions(resource);


分析如下: 见名知意,用资源读取器去解析,之后beadDefiniton的信息会进入到DefaultListBeanFactory里面
简单点说就是: 解析XML里面的信息,转化为DefaultListBeanFactiry能够看懂的信息

在这里插入图片描述

上图所说的意思,跟我们猜的一样!具体的解析不能第一篇文章就说,因为,我快下班了。。以后再说,会仔细说!

如上面几步,不出意外,xml文件中的bean定义已经进入到DefaultListBeanFactory里面了!整体的代码如下:

		// 1. 定义Resource对象
		// 		a. 主要完成的事情: 将path 规范化、合理化
		// 		b. 类加载器的指定
		Resource resource = new ClassPathResource("applicationContext.xml");

		// 2. 定义BeanFactory
		//  	a. 定义一个默认的DefaultListBeanFactory对象
		//		b. 将实现了以下三个类的接口,不再实现依赖注入
		DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

		// 3. 定义资源读取器
		// 		a. 定义资源读取器,其核心是将资源读取器将读取的资源放置到那里!
		BeanDefinitionReader resourceReader = new XmlBeanDefinitionReader(factory);


		// 4. 将配置文件中的Beans定义转化为Bean对象
		// 		a.
		resourceReader.loadBeanDefinitions(resource);

		// Question 1: 哪一行代码完成了Bean的创建
		// Question 2:  哪一行代码完成了Bean的缓存
		Student student = factory.getBean("student", Student.class);


		System.out.println(student.getAge() + ", " + student.getName());

第一篇就到这里了,如果有什么疑问或者问题,请随时提出,谢谢~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值