• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Java > 详解Spring简单容器中的Bean基本加载过程

详解Spring简单容器中的Bean基本加载过程

作者:指 间 生 活 字体:[增加 减小] 来源:互联网 时间:2017-05-28

指 间 生 活 通过本文主要向大家介绍了spring配置文件详解,spring注解详解,spring aop详解,springmvc注解详解,spring框架详解等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

本篇将对定义在 XMl 文件中的 bean,从静态的的定义到变成可以使用的对象的过程,即 bean 的加载和获取的过程进行一个整体的了解,不去深究,点到为止,只求对 Spring IOC 的实现过程有一个整体的感知,具体实现细节留到后面用针对性的篇章进行讲解。

首先我们来引入一个 Spring 入门使用示例,假设我们现在定义了一个类 org.zhenchao.framework.MyBean ,我们希望利用 Spring 来管理类对象,这里我们利用 Spring 经典的 XMl 配置文件形式进行配置:

<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="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的基本配置 -->
  <beanname="myBean"class="org.zhenchao.framework.MyBean"/>

</beans>
</div>

我们将上面的配置文件命名为 spring-core.xml,则对象的最原始的获取和使用示例如下:

// 1. 定义资源
Resource resource = new ClassPathResource("spring-core.xml");
// 2. 利用XmlBeanFactory解析并注册bean定义
XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
// 3. 从IOC容器加载获取bean
MyBean myBean = (MyBean) beanFactory.getBean("myBean");
// 4. 使用bean
myBean.sayHello();
</div>

上面 demo 虽然简单,但麻雀虽小,五脏俱全,完整的让 Spring 执行了一遍配置文件加载,并获取 bean 的过程。虽然从 Spring 3.1 开始 XmlBeanFactory 已经被置为 Deprecated ,但是 Spring 并没有定义出更加高级的基于 XML 加载 bean 的 BeanFactory,而是推荐采用更加原生的方式,即组合使用 DefaultListableBeanFactory 和 XmlBeanDefinitionReader 来完成上诉过程:

Resource resource = new ClassPathResource("spring-core.xml");
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(resource);
MyBean myBean = (MyBean) beanFactory.getBean("myBean");
myBean.sayHello();
</div>

后面的分析你将会看到 XmlBeanFactory 实际上是对 DefaultListableBeanFactory 和 XmlBeanDefinitionReader 组合使用方式的封装,所以这里我们仍然将继续分析基于 XmlBeanFactory 加载 bean 的过程。

一. Bean的解析和注册

Bean的加载过程,主要是对配置文件的解析,并注册 bean 的过程,上图是加载过程的时序图,当我们 new XmlBeanFactory(resource) 的时候,已经完成将配置文件包装成了 Spring 定义的资源,并触发解析和注册。 new XmlBeanFactory(resource) 调用的是下面的构造方法:

publicXmlBeanFactory(Resource resource)throwsBeansException{
  this(resource, null);
}
</div>

这个构造方法本质上还是继续调用了:

publicXmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)throwsBeansException{
  super(parentBeanFactory);
  // 加载xml资源
  this.reader.loadBeanDefinitions(resource);
}
</div>

在这个构造方法里面先是调用了父类构造函数,即 org.springframework.beans.factory.support.DefaultListableBeanFactory 类,这是一个非常核心的类,它包含了基本 IOC 容器所具有的重要功能,是一个 IOC 容器的基本实现。然后是调用了 this.reader.loadBeanDefinitions(resource) ,从这里开始加载配置文件。

Spring 在设计采用了许多程序设计的基本原则,比如迪米特法则、开闭原则,以及接口隔离原则等等,这样的设计为后续的扩展提供了灵活性,也增强了模块的复用性,这也是我看 Spring 源码的动力之一,希望通过阅读学习的过程来提升自己接口设计的能力。Spring 使用了专门的资源加载器对资源进行加载,这里的 reader 就是 org.springframework.beans.factory.xml.XmlBeanDefinitionReader 对象,专门用来加载基于 XML 文件配置的 bean。这里的加载过程为:

  1. 利用 EncodedResource 二次包装资源文件
  2. 获取资源输入流,并构造 InputSource 对象
  3. 获取 XML 文件的实体解析器和验证模式
  4. 加载 XML 文件,获取对应的 Document 对象
  5. 由 Document 对象解析并注册 bean

1.利用 EncodedResource 二次包装资源文件

采用 org.springframework.core.io.support.EncodedResource 对resource 进行二次封装.

2.获取资源输入流,并构造 InputSource 对象

对资源进行编码封装之后,开始真正进入 this.loadBeanDefinitions(new EncodedResource(resource)) 的过程,该方法源码如下:

publicintloadBeanDefinitions(EncodedResource encodedResource)throwsBeanDefinitionStoreException{
  Assert.notNull(encodedResource, "EncodedResource must not be null");
  if (logger.isInfoEnabled()) {
    logger.info("Loading XML bean definitions from " + encodedResource.getResource());
  }

  // 标记正在加载的资源,防止循环引用
  Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
  if (currentResources == null) {
    currentResources = new HashSet<EncodedResource>(4);
    this.resourcesCurrentlyBeingLoaded.set(currentResources);
  }
  if (!currentResources.add(encodedResource)) {
    throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
  }

  try {
    // 获取资源的输入流
    InputStream inputStream = encodedResource.getResource().getInputStream();
    try {
      // 构造InputSource对象
      InputSource inputSource = new InputSource(inputStream);
      if (encodedResource.getEncoding() != null) {
        inputSource.setEncoding(encodedResource.getEncoding());
      }
      // 真正开始从XML文件中加载Bean定义
      return this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    } finally {
      inputStream.close();
    }
  } catch (IOException ex) {
    throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);
  } finally {
    currentResources.remove(encodedResource);
    if (currentResources.isEmpty()) {
      this.resourcesCurrentlyBeingLoaded.remove();
    }
  }
}
</div>

需要知晓的是 org.xml.sax.InputSource 不是 Spring 中定义的类,这个类来自 jdk,是 java 对 XML 实体提供的原生支持。这个方法主要还是做了一些准备工作,按照 Spring 方法的命名相关,真正干活的方法一般都是以 “do” 开头的,这里的 this.doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 就是真正开始加载 XMl 的入口,该方法源码如下:

protectedintdoLoadBeanDefinitions(InputSource inputSource, Resource resource)throwsBeanDefinitionStoreException{
  try {

    // 1. 加载xml文件,获取到对应的Document(包含获取xml文件的实体解析器和验证模式)
    Document doc = this.doLoadDocument(inputSource, resource);

    // 2. 解析Document对象,并注册bean
    return this.registerBeanDefinitions(doc, resource);

  } catch (BeanDefinitionStoreException ex) {
    // 这里是连环catch,省略
  }
}

</div>

方面里面的逻辑还是很清晰的,第一步获取 org.w3c.dom.Document 对象,第二步由该对象解析得到 BeanDefinition 对象,并注册到 IOC 容器中。

3.获取 XML 文件的实体解析器和验证模式

this.doLoadDocument(inputSource, resource) 包含了获取实体解析器、验证模式,以及 Document 对象的逻辑,源码如下:

protectedDocumentdoLoadDocument(InputSource inputSource, Resource resource)throwsException{
  return this.documentLoader.loadDocument(
      inputSource,
      this.getEntityResolver(), // 获取实体解析器
      this.errorHandler,
 



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 详解spring中使用Elasticsearch的代码实现
  • 详解Spring boot上配置与使用mybatis plus
  • 详解Spring Boot中Controller用法
  • 详解Spring Boot 定时任务的实现方法
  • 详解在Spring Boot中使用数据库事务
  • Spring依赖注入的两种方式(根据实例详解)
  • 详解Spring Boot集成MyBatis(注解方式)
  • 详解如何用spring Restdocs创建API文档
  • 详解Spring简单容器中的Bean基本加载过程
  • 详解spring boot配置 ssl

相关文章

  • 2017-08-27Java中的内部类
  • 2017-05-28java 中继承和多态详细介绍
  • 2017-05-28Spring MVC配置双数据源实现一个java项目同时连接两个数据库的方法
  • 2017-05-28Java多线程并发编程(互斥锁Reentrant Lock)
  • 2017-05-28面向对象和面向过程的区别(动力节点java学院整理)
  • 2017-05-28jedis操作redis的几种常见方式总结
  • 2017-05-28Java Map简介_动力节点Java学院整理
  • 2017-05-28springboot实现FastJson解析json数据的方法
  • 2017-05-28Java本地缓存的实现代码
  • 2017-05-2830分钟入门Java8之默认方法和静态接口方法学习

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 详解Java单元测试Junit框架实例
    • Java 中的 BufferedWriter 介绍_动力节点Java学院整理
    • 深入讲解Java 9中的九个新特性
    • JVM 方法调用之动态分派(详解)
    • Java中static的特点
    • java中TCP/UDP详细总结
    • java中将一个List等分成n个list的工具方法(推荐)
    • 浅谈JSP与Servlet传值及对比(总结)
    • Java 加密解密基础分类及模式归纳整理
    • Java 选择排序、插入排序、希尔算法实例详解

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有