欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring容器的基本实现

程序员文章站 2022-06-25 09:40:49
Spring容器的基本实现(一)1 容器基本用法​bean是Spring中最核心的东西了,因为Spring就像是一个大水桶,而bean就像是容器中的水,我们先看看bean的定义.public class TestBean { private String testStr = "testStr"; public String getTestStr() { return testStr; } public void setTestStr(String...

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个类.

Spring容器的基本实现

  • 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的层次类图:

Spring容器的基本实现

  • 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的层次类图和各个类的作用

Spring容器的基本实现
Spring容器的基本实现

ResourceLoader:定义资源加载器,主要应用于根据给定的资源文件地址返回对应的Resource
BeanDefinitionReader:主要定义资源文件读取并转换为BeanDefinition的各个功能
EnvironmentCapable:定义获取Environment方法
DocumentLoader:定义从资源文件加载到转换为Document的功能
AbstractBeanDefinitionReader:对EnvironmentCapable、BeanDefinitionReader类定义的功能进行实现
BeanDefinitionDocumentReader:定义读取Document并注册BeanDefinition功能
BeanDefinitionParserDelegate:定义解析Element的各种方法
​ 整个XML配置文件读取的大致流程,在XmlBeanDefinitionReader中主要包含以下几步处理

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

4容器的基础 XmlBeanFactory

​ 我们对容器功能有了一个大概的了解,我们现在重新来看一下代码,接下来深入分析一下功能的代码实现:

XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

​ 通过XmlBeanFactory初始化时序图我们来看一下上面代码的执行逻辑

Spring容器的基本实现

  1. 第一步调用了ClassPathResource的构造函数来构造Resource资源文件的实例对象,
  2. 第二步返回了resource资源文件,有了resource资源文件的实例对象我们就可以进行XmlBeanFactory的初始化了.
  3. 第三步调用了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

相关标签: Spring java