Spring实战系列(三)了解容器的基本实现

发布时间:2023年12月26日

我们可以通过GitHub或者码云下载spring-framework源码,这边是基于5.X版本进行下载学习的。

地址https://github.com/spring-projects/spring-framework

分析Spring源码是非常一件的难的事情,只能一步步学习,一步步记录。

? ? ? ?前面在第一章Spring整体架构中,bean是Spring中最核心的部分,在没有接触Spring的时候,我们使用bean是通过new 的方式进行创建,spring bean容器就是将这些对象交给spring去创建和管理,我们只需要在配置文件或者注解的方式告诉spring容器需要创建哪些bean对象。所以需要先在配置文件中定义好需要创建的bean对象,这些配置统称为bean定义配置元数据信息,spring容器通过读取这些bean配置元数据信息来构建和组装我们需要的对象,

我们通过一个入门案例来揭开Spring 容器是如何实现的

1.? 创建一个简单的bean
public class TestBean {

    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
2.??定义配置元数据信息,通过XML的方式
<?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.spring.demo.beans.TestBean">
        <property name="msg" value="put test bean msg"/>
    </bean>
</beans>
3.? ?测试通过Spring获取bean
public class TestBeanMain {
    @Test
    public void testBeanLoad(){
        //在3.2版本以后不推荐使用 这里方便了解Spring内部原理
        // spring主要有2个容器,一个BeanFactory 一个ApplicationContext,后者是前者一个扩展容器
        BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("bean-config.xml"));
        TestBean testBean = (TestBean) xmlBeanFactory.getBean("testBean");
        System.out.println(testBean.getMsg());
    }
}

运行结果:

用于实现上面功能的是org.springframework.bean.jar
功能分析

? ? ?通过上面的一个简单案例,主要完成的功能步骤如下:

  • 读取配置文件bean-config.xml
  • 根据配置文件中的配置元信息找到对应类的配置,并进行反射实例化
  • 调用实例化的实例
源码分析
XmlBeanFactory对DefaultListableBeanFactory进行了扩展,主要用于从XML文档中读取BeanDefinition,注册和获取bean都是从父类通过继承的方式去实的。代码如下:

进入XmlBeanDefinitionReader类的loadBeanDefinitions方法,这是资源加载的真正实现。

	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		// 对资源文件进行编码处理
		return loadBeanDefinitions(new EncodedResource(resource));
	}
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		// 资源不可为空验证
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Loading XML bean definitions from " + encodedResource);
		}
        // 通过属性来记录已经加载过的资源
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        // 添加失败抛出异常 当已存在
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		//从encodedResource中获取已经封装好的resource资源并从中获取inputStream
		try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				// 设置编码
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			//真正进入加载核心内容
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			//加载完记录中移除
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			// 获取XML文件的验证模式,对XML进行加载并得到对应的Document
			Document doc = doLoadDocument(inputSource, resource);
			// 返回根据XML文件中注册bean的个数
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
        //省略其他代码
		.......
	}

后续会对上面XML验证加载以及获取bean信息进行深入。

文章来源:https://blog.csdn.net/m0_37479246/article/details/135182177
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。