Spring容器的基本实现
Spring容器的基本实现
****此文档为本人阅读《Spring源码深度解析》时的阅读笔记
1 容器基本用法
bean是Spring中最核心的东西了,因为Spring就像是一个大水桶,而bean就像是容器中的水,我们先看看bean的定义.
public class TestBean {
private String testStr = "testStr";
public String getTestStr() {
return testStr;
}
public void setTestStr(String testStr) {
this.testStr = testStr;
}
}
bean没有任何特别之处,但是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="TestBean" class="com.study.bean.TestBean"></bean>
</beans>
上面的配置中我们看到了bean的声明方式,Spring的入门实例这里已经结束了,我们就可以写测试代码了进行测试了.
@SuppressWarnings("deprecation")
public class beanFactoryTest {
@Test
public void testSimpleLoad() {
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
TestBean bean = (TestBean) bf.getBean("TestBean");
Assert.assertEquals("testStr",bean.getTestStr());
}
}
很快我们看到了我们期待的结果:在idea中显示了Green Bar;
2 功能分析
对于Spring有一定使用经验的人应该都可以猜出来,这段测试代码完成的功能无非是以下几点:
(1)读取配置文件beanFactoryTest.xml.
(2)根据beanFactoryTest.xml.中的配置找到对应的类的配置,并实例化.
(3)调用实例化后的实例
下面是一个简单的设计类图可以帮助我们更清楚的理解.如果像完成我们预想的功能,至少需要3个类.
- ConfigReader:读取配置文件,然后放置在内存中
-
ReflectionUtil:根据配置文件中的配置进行反射实例化,例如beanFactoryTest.xml中的
<bean id="TestBean" class="com.study.bean.TestBean"></bean>
,我们就可以根据com.study.bean.TestBean进行实例化. - APP:用于整个逻辑的串联
3 Spring的结构组成
3.1 核心类介绍
1 DefaultListableBeanFactory
XmlBeanFactory继承自DefaultListableBeanFactory,而DefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册及加载的默认实现,而对于XmlBeanFactory与DefaultListableBeanFactory不同的地方就是XmlBeanFactory使用的自定义的XML读取器XmlBeanDefinitionReader,实现了个性化的BeanDefinitionReader读取;
我们再来看看DefaultListableBeanFactory的层次类图:
- AliasRegistry:定义对alias的简单增删改等操作
- SimpleAliasRegistry:主要使用map作为alias的缓存,并对接口AliasRegistry进行实现
- SingletonBeanRegistry:定义对单例的注册及获取
- BeanFactory:定义获取bean及bean的各种属性
- DefaultSingletonBeanRegistry:默认对接口SingletonBeanRegistry各函数的实现
- HierarchicalBeanFactory:继承BeanFactory,也就是在BeanFactory定义的功能的基础上增加了对parentFactory的支持
- BeanDefinitionRegistry:定义对BeanDefinition的各种增删改操作
- FactoryBeanRegistrySupport:在DefaultSingletonBeanRegistry基础上增加了对FactoryBean的特殊处理功能
- ConfigurableBeanFactory:提供配置Factory的各种方法
- ListableBeanFactory:根据各种条件获取bean的配置清单
- AbstractBeanFactory:综合FactoryBeanRegistrySupport和ConfigurationBeanFactory的功能
- AutowireCapableBeanFactory:提供创建bean、自动注入、初始化以及应用bean的后处理器
- AbstractAutowireCapableBeanFactory:综合AbstractBeanFactory并对接口AutowireCapableBeanFactory进行实现
- ConfigurableListableBeanFactory :BeanFactory配置清单,指定忽略类型及接口等
- DefaultListableBeanFactory:综合上面所有功能,主要是对Bean注册后的处理
XmlBeanFactory对DefaultListableBeanFactory类进行了扩展,主要从XML文档中读取BeanDefinition,对于注册和读取Bean都是从父类DefaultListableBeanFactory继承的方法去实现,而惟独与父类不同的个性化实现就是增加了XmlBeanDefinitionReader类型的reader属性.在XmlBeanFactory中主要使用reader属性对资源文件进行读取和注册.
2 XmlBeanDefinitionReader
XML配置文件的读取时Spring中重要的功能,因为Spring的大部分功能都是以配置作为切入点的,那么我们可以从XmlBeanDefinitionReader中梳理一下资源文件的读取,解析以及注册的流程,首先我们看看XmlBeanDefinitionReader的层次类图和各个类的作用
ResourceLoader:定义资源加载器,主要应用于根据给定的资源文件地址返回对应的Resource
BeanDefinitionReader:主要定义资源文件读取并转换为BeanDefinition的各个功能
EnvironmentCapable:定义获取Environment方法
DocumentLoader:定义从资源文件加载到转换为Document的功能
AbstractBeanDefinitionReader:对EnvironmentCapable、BeanDefinitionReader类定义的功能进行实现
BeanDefinitionDocumentReader:定义读取Document并注册BeanDefinition功能
BeanDefinitionParserDelegate:定义解析Element的各种方法
整个XML配置文件读取的大致流程,在XmlBeanDefinitionReader中主要包含以下几步处理
- 通过继承AbstractBeanDefinitionReader中的方法来使用ResourceLoader将资源文件路径转换为对应的Resource文件.
- 通过DocumentLoader对Resource文件进行转换,将Resource文件转换Document文件.
- 通过实现接口BeanDefinitionDocumentReader的DefaultBeanDefinitionDocumentReader类对Document进行解析,并使用BeanDefinitionParserDelegate对Element进行解析.
4容器的基础 XmlBeanFactory
我们对容器功能有了一个大概的了解,我们现在重新来看一下代码,接下来深入分析一下功能的代码实现:
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
通过XmlBeanFactory初始化时序图我们来看一下上面代码的执行逻辑
- 第一步调用了ClassPathResource的构造函数来构造Resource资源文件的实例对象,
- 第二步返回了resource资源文件,有了resource资源文件的实例对象我们就可以进行XmlBeanFactory的初始化了.
- 第三步调用了XmlBeanFactory的构造方法(Resource实例作为参数的构造函数).代码如下
public XmlBeanFactory(Resource resource) throws BeansException {
//调用内部其他构造函数
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
//忽略指定接口的自动装配功能(BeanNameAware.class,BeanFactoryAware.calss,BeanClassLoaderAware.class)
super(parentBeanFactory);
//加载资源的真正实现
this.reader.loadBeanDefinitions(resosurce);
}
4.第四步在XmlBeanFactory的构造方法中调用了XmlBeanDefinitionReader的loadBeanDefinitions(resosurce)方法.我们来看看这个方法做了什么事情:
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
// 调用内部重载方法
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
try {
//获取文件流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
// 获取InputSource
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//调用doLoadBeanDefinitions()方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
}
5.第五步在XmlBeanDefinitionReader的构造方法中调用了doLoadBeanDefinitions方法:我们来看看做了些什么事情
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//从获取inputSource中Document对象
Document doc = doLoadDocument(inputSource, resource);
//解析及注册bean信息
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
}
doLoadBeanDefinitions方法做了三件事:
- 获取对XML文件的验证模式(分为DTD和XSD两种):保证了xml文件的正确性
- 加载xml文件,并得到document对象
- 根据返回的document注册Bean信息
6.第五步在doLoadBeanDefinitions的方法中调用了doLoadDocument方法:
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
//调用documentLoader中的loadDocument方法
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
//获取XML的验证模式
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = getValidationMode();
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
int detectedMode = detectValidationMode(resource);
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
return VALIDATION_XSD;
}
//documentLoader中的loadDocument方法
/**
首先创建DocumentBuilderFactory,再通过DocumentBuilderFactory创建DocumentBuilder,进而解析inputSource来返回Document对象
*/
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
7.第七步在doLoadBeanDefinitions的方法中调用了registerBeanDefinitions方法:解析及注册bean信息
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//获取默认BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 统计注册前BeanDefinition的加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
//加载及注册bean信息
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
记录本次加载的BeanDefinition的个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
//处理解析
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
//处理profile属性(一套代码适用于不同环境)
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
//解析前处理,留给子类实现
preProcessXml(root);
//解析注册bean
parseBeanDefinitions(root, this.delegate);
//解析后处理,留给子类实现
postProcessXml(root);
this.delegate = parent;
}
//解析并注册BeanDefinition
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//默认处理
parseDefaultElement(ele, delegate);
}
else {
//自定义命名空间进行解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
//自定义命名空间进行解析
delegate.parseCustomElement(root);
}
}
本文地址:https://blog.csdn.net/weixin_44006699/article/details/112562788
上一篇: 腾讯新开源的插件化框架 Shadow,原来是这么玩的
下一篇: 牛牛晾衣服