【Spring源码深度解析学习系列】容器的基础XmlBeanFactory(二)
一、配置文件封装
Spring的配置文件读取是通过ClassPathResource进行封装的,如new ClassPathResource("test.xml"),那么ClassPathResource完成的功能是什么呢?
在java中,将不同来源的资源抽象成URL,通过注册不同的handler(URLStreamHandler)来处理不同来源的资源的读取逻辑,一般handler的类型使用不同前缀(协议,Protocol)来识别,如:file: http: jar: 等,然而URL没有默认定义相对Classpath或ServletContext等资源的handler,虽然可以注册自己的URLStreamHandler来解析特定的URL前缀(协议),比如“classpath:”,这个需要了解URL的实现机制,而且url也没有提供一些基本的方法,如检查当前资源是否存在、检查当前资源是否可读等方法。因而Spring对其内部使用到的资源实现了自己的抽象结构:Resource接口来封装底层资源:
public interface InputStreamSource { /**
* Return an {@link InputStream} for the content of an underlying resource.
* <p>It is expected that each call creates a <i>fresh</i> stream.
* <p>This requirement is particularly important when you consider an API such
* as JavaMail, which needs to be able to read the stream multiple times when
* creating mail attachments. For such a use case, it is <i>required</i>
* that each {@code getInputStream()} call returns a fresh stream.
InputStream getInputStream() throws IOException; }
public interface Resource extends InputStreamSource { /**
* Determine whether this resource actually exists in physical form.
* <p>This method performs a definitive existence check, whereas the
* existence of a {@code Resource} handle only guarantees a valid
* descriptor handle.
*/
boolean exists(); /**
* Indicate whether the contents of this resource can be read via
* {@link #getInputStream()}.
* <p>Will be {@code true} for typical resource descriptors;
* note that actual content reading may still fail when attempted.
* However, a value of {@code false} is a definitive indication
* that the resource content cannot be read.
* @see #getInputStream()
*/
boolean isReadable(); /**
* Indicate whether this resource represents a handle with an open stream.
* If {@code true}, the InputStream cannot be read multiple times,
* and must be read and closed to avoid resource leaks.
* <p>Will be {@code false} for typical resource descriptors.
*/
boolean isOpen(); /**
* Return a URL handle for this resource.
* @throws IOException if the resource cannot be resolved as URL,
* i.e. if the resource is not available as descriptor
*/
URL getURL() throws IOException; /**
* Return a URI handle for this resource.
* @throws IOException if the resource cannot be resolved as URI,
* i.e. if the resource is not available as descriptor
* @since 2.5
*/
URI getURI() throws IOException; /**
* Return a File handle for this resource.
* @throws java.io.FileNotFoundException if the resource cannot be resolved as
* absolute file path, i.e. if the resource is not available in a file system
* @throws IOException in case of general resolution/reading failures
* @see #getInputStream()
*/
File getFile() throws IOException; /**
* Determine the content length for this resource.
* @throws IOException if the resource cannot be resolved
* (in the file system or as some other known physical resource type)
*/
long contentLength() throws IOException; /**
* Determine the last-modified timestamp for this resource.
* @throws IOException if the resource cannot be resolved
* (in the file system or as some other known physical resource type)
*/
long lastModified() throws IOException; /**
* Create a resource relative to this resource.
* @param relativePath the relative path (relative to this resource)
* @return the resource handle for the relative resource
* @throws IOException if the relative resource cannot be determined
*/
Resource createRelative(String relativePath) throws IOException; /**
* Determine a filename for this resource, i.e. typically the last
* part of the path: for example, "myfile.txt".
* <p>Returns {@code null} if this type of resource does not
* have a filename.
*/
String getFilename(); /**
* Return a description for this resource,
* to be used for error output when working with the resource.
* <p>Implementations are also encouraged to return this value
* from their {@code toString} method.
* @see Object#toString()
*/
String getDescription(); }
InputStreamSource封装任何能返回InputStream的类,比如File、Classpath下的资源和 Byte Array对象。它只有一个方法定义:getInputStream(),该方法返回一个新的InputStream对象。
Resource接口抽象了所有Spring内部使用到的底层资源:File、URL、Classpath等,首先、它定义了3个判断当前资源状态的方法:存在性(exists)、可读性(isReaddable)、是否处于打开状态(isOpen)另外Resource接口还提供了不同资源到URL、URI、File类型的转换,以及获取lastModified属性、文件名(不带路径信息的文件名,getFilename())的方法。为了便于操作,Resource还提供了基于当前资源创建一个相对资源的犯法:createRelative()。在错误处理中需要详细打印出错的资源文件,因而Resource还提供了getDescription()方法用于在错误处理中的打印信息。
对不同来源的资源文件都有相应的Resource实现:文件(FileSystemResource)、Classpath资源(ClassPathResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等。
加载资源文件的代码:
Resource resource = new ClassPathResource("beanFactoryTest.xml");
InputStream inputStream = resource.getInputStream();
ClassPathResource的实现:
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);
}
else if (this.classLoader != null) {
is = this.classLoader.getResourceAsStream(this.path);
}
else {
is = ClassLoader.getSystemResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
}
return is;
}
FileInputStream的实现:
public InputStream getInputStream() throws IOException {
return new FileInputStream(this.file);
}
当通过Resource相关类完成了对配置文件进行封装后配置文件的读取工作就全权交给XmlBeanDefinitonReader来处理了。
XmlBeanFactory的初始化有若干方法,Spring中提供了很多的构造函数,以下为使用Resource实例作为构造函数参数的办法。
public XmlBeanFactory(Resource resource) throws BeansException {
//调用XmlBeanFactory(Resource,BeanFactory)构造方法
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
public void ignoreDependencyInterface(Class<?> ifc) {
this.ignoredDependencyInterfaces.add(ifc);
}
ignoreDependencyInterface的主要功能是忽略给定接口的自动装配功能。这样做的目的是什么呢?举例来说,当A中有属性B,那么当Spring在获取A的Bean的时候如果其属性B还没有初始化,那么Spring会自动初始化B,这也是Spring中提供的一个重要特性。但是某些情况下,B不会被初始化,其中的一种情况就是B实现了BeanNameAware接口,Spring中是这样介绍的:自动装配时忽略给定的依赖接口,典型应用是通过其他方式解析Application上下文注册依赖,类似于BeanFactory通过BeanFactoryAware进行注册或者ApplicationContext通过ApplicationContextAware进行注入。
二、加载Bean
【Spring源码深度解析学习系列】容器的基础XmlBeanFactory(二)的更多相关文章
- 【Spring源码深度解析学习系列】Bean的加载(六)
Bean的加载所涉及到的大致步骤: 1)转换对应beanName 为什么需要转换beanName呢?因为传入的参数可能是别名,也可能是FactoryBean,所以需要一系列的解析,这些解析内容包括如下 ...
- 【Spring源码深度解析学习系列】复杂标签属性解析(四)
一.创建用于属性承载的BeanDefinition BeanDefiniton是一个接口,在Spring中存在三种实现:RootBeanDefinition.ChildBeanDefinition.G ...
- 【Spring源码深度解析学习系列】默认标签解析(三)
Spring的标签包括默认标签和自定义标签两种 默认标签的解析方法: ###DefaultBeanDefinitionDocumentReader.java### private void parse ...
- 【Spring源码深度解析学习系列】核心类介绍(一)
一.DefaultListableBeanFactory 首先看一下结构 由图可知XmlBeanFactory继承自DefaultListableBeanFactory,而DefaultListabl ...
- 【Spring源码深度解析学习系列】注册解析的BeanDefinition(五)
对于配置文件,解析和装饰完成之后,对于得到的beanDefinition已经可以满足后续的使用要求了,还剩下注册,也就是processBeanDefinition函数中的BeanDefinitionR ...
- spring源码深度解析— IOC 之 容器的基本实现
概述 上一篇我们搭建完Spring源码阅读环境,spring源码深度解析—Spring的整体架构和环境搭建 这篇我们开始真正的阅读Spring的源码,分析spring的源码之前我们先来简单回顾下spr ...
- Spring源码分析(四)容器的基础XmlBeanFactory
摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 经过Spring源码分析(二)容器基本用法和Spring源码分析(三)容 ...
- spring源码深度解析— IOC 之 开启 bean 的加载
概述 前面我们已经分析了spring对于xml配置文件的解析,将分析的信息组装成 BeanDefinition,并将其保存注册到相应的 BeanDefinitionRegistry 中.至此,Spri ...
- spring源码深度解析— IOC 之 默认标签解析(上)
概述 接前两篇文章 spring源码深度解析—Spring的整体架构和环境搭建 和 spring源码深度解析— IOC 之 容器的基本实现 本文主要研究Spring标签的解析,Spring的标签 ...
随机推荐
- Exception in thread "main" java.lang.IllegalArgumentException
1.错误描述 Exception in thread "main" java.lang.IllegalArgumentException: Cannot format given ...
- javaWeb之自动发送邮件生日祝福(ServletContextListener监听)
在看完本随笔仍然不理解的可以看 javaWeb邮箱发送 :里面有具体的邮箱服务器配置 企业在员工生日当天发送邮箱生日祝福: 一般是用监听器完成: 而合适的监听是ServletContextLis ...
- OpenStack_I版 2.keystone部署
生成keystone默认证书,指定用户 修改keystone主配置文件 第625行,修改数据库连接方式 修改完成同步数据库 同步完成可以查看数据库是否有表生成 为了以后调试keystone方便,现 ...
- jquery初始化的三种方式
第一种 $(document).ready(function(){ alert("第一种方法."); }); 第二种 $(function(){ alert("第二种方法 ...
- VS2017 启动调试报错:ID为{....}进程未启动解决方案
今天遇到这么一个问题,打开VS启动调试,始终报错,如下图: 我重启VS,甚至重启电脑都不得行,那个进程号还在变化,就在网上查找资料,各式各样的解决方案,这里我记录我成功的方案. 打开项目文件地址,在解 ...
- cisco linksys ea3500 刷机 openwrt
家中router改造成千兆华为A1,淘汰下来的cisco linksys ea3500 终于可以去刷机 openwrt,尽情折腾啦! 分享步骤: 准备文件 https://archive.openw ...
- SOA和微服务架构
微服务架构强调的第一个重点就是业务系统需要彻底的组件化和服务化,原有的单个业务系统会拆分为多个可以独立开发,设计,运行和运维的小应用.这些小应用之间通过服务完成交互和集成.每个小应用从前端web ui ...
- TensorLayer官方中文文档1.7.4:API – 可视化
API - 可视化¶ TensorFlow 提供了可视化模型和激活输出等的工具 TensorBoard. 在这里,我们进一步提供一些可视化模型参数和数据的函数. read_image(image[, ...
- 【BZOJ2428】均分数据(模拟退火)
[BZOJ2428]均分数据(模拟退火) 题面 BZOJ 题解 先说说黄学长的做法: 当温度比较高的时候,贪心 每次随机一个数,把他放进当前和最少的那一组里面 温度足够低的时候就完全随机然后转移 这样 ...
- 配置linux软件下载跟新地址
/etc/yum.repos.d/CentOS-Base.repo 直接到mirrors.aliyum.com下载 diff:比较