容器的基本实现

Spring中的bean是最核心的东西,因为Spring就像是一个大水桶,bean就像是容器中的水,水桶如果脱离了水那么就没有什么意义了。

package container;
public class MyTestBean {
    private String testStr = "testStr";
    public String getTestStr() {
	return testStr;
    }
    public void setTestStr(String testStr) {
	this.testStr = testStr;
    }
}

一个简单的JavaBean对象没有任何特别之处,的确,Spring的目的就是让我们的bean能成为一个纯粹的POJO。

<?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="myTestBean" class="container.MyTestBean" />
</beans>

上面的配置中可以看到bean的声明方式,尽管Spring中bean的元素定义着N种属性来支持我们的业务的各种应用,但是我们只要声明成这种样子就基本能满足我们大多数应用了

package container;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class BeanFactoryTest {

	@Test
	public void testSimpleLoad() {
		BeanFactory bf = new XmlBeanFactory(new ClassPathResource("container/BeanFactoryTest.xml"));
		MyTestBean bean = (MyTestBean) bf.getBean("myTestBean");
		assertEquals("testStr", bean.getTestStr());
	}
}

上面这段代码应该是Spring框架的最基本功能,那么这样一句简单的代码都执行了什么样的逻辑呢?可以简单的理解为这几点:
1、读取配置文件BeanFactoryTest.xml
2、根据BeanFactoryTest.xml中的配置找到对应的类配置并实例化
3、调用实例化后的实例

容器的基本实现

ConfigReader用于读取及验证配置文件,我们要用配置文件里面的东西,首先要做的是读取,然后放到内存中
ReflectionUtil用于根据配置文件中的配置进行反射实例化
App用于完成整个逻辑的串联

按照最原始的思维方式,整个过程无非如此,但是作为一个风靡世界的优秀源码当然不止这么简单

工程搭建

首先找到上一篇文章中编译好的spring-framework源码,导入spring-beans项目

容器的基本实现

这里导入spring-beans项目后报错,缺失spring-core模块,解决办法:导入spring-core项目到eclipse中。错误消失

容器的基本实现

引入依赖消除掉错误后,终于可以看到源码了,可以看到spring居然用了N多的代码实现了这个看似简单的功能,那么这些代码都是做什么的呢?我们继续深入。

Spring的结构组成

beans包的层级结构:
src/main/java:用于展现Spring的主要逻辑
src/main/resources:用于存放系统的配置文件
src/test/java:用于对主要逻辑进行单元测试
src/test/resources:用于存放测试用的配置文件

核心类介绍

DefaultListableBeanFactory

XmlBeanFactory继承自DefaultListableBeanFactory,而DefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册及加载bean的默认实现。XmlBeanFactory中使用了自定义的XML读取器XmlBeanDefinitionReader,实现了个性化的BeanDefinitionReader读取,DefaultListableBeanFactory继承了AbstractAutowireCapableBeanFactory并实现了ConfigurableListableBeanFactory以及BeanDefinitionRegistry接口

容器的基本实现

从上面类图以及层次结构图中,可以很清楚地从全局角度了解DefaultListableBeanFactory的脉络,下面简单介绍一下上面类图中各个类的作用
AliasRegistry:定义对alias的简单增删改差等操作
SimpleAliasRegistry:主要使用map作为alias的缓存,并对接口AliasRegistry进行实现
SingletonBeanRegistry:定义对单例的注册及获取
BeanFactory:定义获取bean及bean的各种属性
DefailtSingletonBeanFactory:对接口SingletonBeanRegistry各函数的实现
HierarchicalBeanFactory:继承BeanFactory,也就是在BeanFactory定义的功能的基础上增加了对parentFactory的支持
BeanDefinitionRegistry:定义对BeanDefinition的各种增删改差操作
FactoryBeanRegistrySupport:在DefaultSingletonBeanRegistry基础上增加了对FactoryBean的特殊处理功能
ConfigurableBeanFactory:提供配置Factory的各种方法
ListableBeanFactory:根据各种条件获取bean的配置清单
AbstractBeanFactory:综合FactoryBeanRegistrySupport和ConfigurableBeanFactory的功能
AutowireCapableBeanFactory:提供创建bean、自动注入、初始化以及应用 bean的后处理
AbstractAutowireCapableBeanFactory:综合AbstractBeanFactory并对接口AutowireCapableBeanFactory进行实现
ConfigurableListableBeanFactory:BeanFactory配置清单,指定忽略类型及接口等
DefaultListableBeanFactory:综合上面所有功能,主要是对Bean注册后的处理

XmlBeanFactory对DefaultListableBeanFactory类进行了扩展,主要用于从XML文档中读取BeanDefinition,对于注册及获取Bean都是从父类DefaultListableBeanFactory继承的方法去实现,唯独与父类不同的个性化实现就是增加了XmlBeanDefinitionReader类型的reader属性,在XmlBeanFactory中主要使用reader属性对资源文件进行读取和注册

XmlBeanDefinitionReader

Xml配置文件的读取时Spring中重要的功能,因为Spring的大部分功能都是以配置作为切入点的,我们可以从XmlBeanDefinitionReader中梳理一下资源文件的读取、解析及注册的大致脉络,首先我们看看各个类的功能

ResourceLoader:定义资源加载器,主要应用于根据给定的资源文件地址返回对应的Resource
BeanDefinitionReader:主要定义资源文件读取并转化为BeanDefinition的各个功能
EnvironmentCapable:定义获取Environment方法
DocumentLoader:定义从资源文件加载到转换为Document的功能
AbstractBeanDefinitionReader:对EnvironmentCapable、BeanDefinitionReader:类定义的功能进行实现。
BeanDefinitionDocumentReader:定义读取Document并主持BeanDefinition功能
BeanDefinitionParserDelegate:定义解析Eliment的各种方法

经过以上分析,大致可以梳理出整个xml配置文件读取的流程

容器的基本实现

1、通过继承自AbstractBeanDefinitionReader中的方法,来使用ResourceLoader将资源文件路径转换为对应的Resource文件
2、通过DocumentLoader对Resource文件进行转换,将Resource文件转换为Document文件
3、通过实现接口BeanDefinitionDocumentReader的DefaultBeanDefinitionDocumentReader类对Document进行解析,并使用BeanDefinitionParserDelegate对Element进行解析

(0)
上一篇 2018-11-04 17:35
下一篇 2018-11-08 20:48

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

评论列表(2条)

  • 有梦想的人不睡觉
    有梦想的人不睡觉 2019-03-25 23:54

    刚刚学到spring,总结的很好!:stuck_out_tongue_winking_eye: