在第二节中我们销毁了老的bean,第三节中有创建了一个新的DefaultListableBeanFactory 类型的工厂,接着又创建了一个 XmlBeanDefinitionReade类型的reader,顾名思义,这个reader就是去读取我们的配置文件,然后解析,完成初始化,在这一节里,我们要完成的是定位配置文件。
1.2.2.1.1.3.1.1 loadBeanDefinitions(configLocations): 定义在 XmlBeanDefinitionReader
的抽象父类 -AbstractBeanDefinitionReader 中:
通过循环参数数组:调用函数 loadBeanDefinitions(locations[i]) ,在该函数中又直接调用: loadBeanDefinitions(location, null) ;
原型 为: loadBeanDefinitions(String location, Set actualResources) 定义如下:
====================================================================
// 这里得到当前定义的 ResourceLoader , 默认的我们使用 DefaultResourceLoader
ResourceLoader resourceLoader = getResourceLoader() ;
// 如果没有找到我们需要的 ResourceLoader ,直接抛出异常
if (resourceLoader == null ) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available" );
}
/**
* 由 getResourceLoader() 函数可知 resourceLoader 为
* PathMatchingResourcePatternResolver 类型,而
* PathMatchingResourcePatternResolver 继承 ResourcePatternResolver
* 这里处理我们在定义位置时使用的各种 pattern, 需要 ResourcePatternResolver 来完成
*/
if (resourceLoader instanceof ResourcePatternResolver) {
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location) ;
/**
* 自此对资源文件的装载过程结束。下面是对文件的解析和初始化 bean 过程,下面的函数最终
* 会调用 XmlBeanDefinitionReader 类的 loadBeanDefinitions(EncodedResource
* encodedResource)
*/
int loadCount = loadBeanDefinitions(resources) ;
if (actualResources != null ) {
for ( int i = 0; i < resources. length ; i++) {
actualResources.add(resources[i]) ;
}
}
if ( logger .isDebugEnabled()) {
logger .debug( "Loaded " + loadCount + " bean definitions from location pattern [" + location + "]" );
}
return loadCount;
} catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]" , ex);
}
} else {
// Can only load single resources by absolute URL.
// 这里通过 ResourceLoader 来完成位置定位
Resource resource = resourceLoader.getResource(location);
// 这里已经把一个位置定义转化为 Resource 接口,可以供 XmlBeanDefinitionReader 来使用了
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null ) {
actualResources.add(resource) ;
}
if ( logger .isDebugEnabled()) {
logger .debug( "Loaded " + loadCount + " bean definitions from location [" + location + "]" );
}
return loadCount;
}
====================================================================
描述:
1.2.2.1.1.3.1.1.1 getResourceLoader() :从类图中可以看出在 AbstractBeanDefinitionReader 中有 private ResourceLoader resourceLoader ;即是此处的 resourceLoader ;然后注意到 XmlBeanDefinitionReader 的构造函数:
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super (registry);
}
回到父类 AbstractBeanDefinitionReader 的构造函数:
====================================================================
Assert.notNull (registry, "BeanDefinitionRegistry must not be null" );
this . registry = registry;
// Determine ResourceLoader to use.
if ( this . registry instanceof ResourceLoader) {
this . resourceLoader = (ResourceLoader) this . registry ;
} else {
this . resourceLoader = new PathMatchingResourcePatternResolver ();
}
====================================================================
可以看出在构造函数中,如果传入的参数是一个 ResourceLoader 类型的对象,那么他将在类型转化后赋给 resourceLoader 。回到 XmlBeanDefinitionReader 创建的地方,即在类: AbstractXmlApplicationContext 的 loadBeanDefinitions 函数里。看到传入的参数是: beanFactory ,找到 beanFactory 的定义处 —AbstractRefreshableApplicationContext 的函数: refreshBeanFactory 里,为:
DefaultListableBeanFactory beanFactory = createBeanFactory() ;由类图中可以看出 beanFactory 不是一个 ResourceLoader 类型,所以执行:
this . resourceLoader = new PathMatchingResourcePatternResolver () ;在构造函数可以看见实际上是创建了一个 DefaultResourceLoader
1.2.2.1.1.3.1.1.2 getResources(location) :由上面的解释可以知道 resourceLoader 实际上是 PathMatchingResourcePatternResolver 类型,
所以在 PathMatchingResourcePatternResolver 类中的找到 getResources(String locationPattern) 方法如下:
====================================================================
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull (locationPattern, "Location pattern must not be null" );
// 如果 locationPattern 是以字符串: “ classpath*: ”开始。
if (locationPattern.startsWith( CLASSPATH_ALL_URL_PREFIX )) {
if (getPathMatcher().isPattern(locationPattern.substring( CLASSPATH_ALL_URL_PREFIX .length()))) {
// 一个 classpath 资源。
return findPathMatchingResources(locationPattern);
} else {
// 多个 classpath 资源
return findAllClassPathResources(locationPattern.substring( CLASSPATH_ALL_URL_PREFIX .length()));
}
} else {
// Only look for a pattern after a prefix here
// (to not get fooled by a pattern symbol in a strange prefix).
int prefixEnd = locationPattern.indexOf( ":" ) + 1;
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
// 文件类型
return findPathMatchingResources(locationPattern);
} else {
// a single resource with the given name
return new Resource[] {getResourceLoader().getResource(locationPattern) };
}
}
}
====================================================================
我们关注最后一行,即红色部分,这一行的本质是去调用 DefaultResourceLoader 类的
Resource getResource(String location) 方法:方法如下:
====================================================================
public Resource getResource(String location) {
Assert .notNull (location, "Location must not be null" );
// 如果是类路径的方式,那需要使用 ClassPathResource 来得到 bean 文件的资源对象
if (location.startsWith( CLASSPATH_URL_PREFIX )) {
return new ClassPathResource(location.substring( CLASSPATH_URL_PREFIX .length()), getClassLoader());
} else {
try {
// Try to parse the location as a URL...
// 如果是 URL 方式,使用 UrlResource 作为 bean 文件的资源对象
URL url = new URL(location);
return new UrlResource(url);
} catch (MalformedURLException ex) {
// 如果都不是,那我们只能委托给子类由子类来决定使用什么样的资源对象了
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}
====================================================================
我们的 FileSystemXmlApplicationContext 本身就是是 DefaultResourceLoader 的实现类,他实现了以下的接口:
====================================================================
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith( "/" )) {
path = path.substring(1);
}
// 这里使用文件系统资源对象来定义 bean 文件
return new FileSystemResource (path);
}
====================================================================
这样代码就回到了 FileSystemXmlApplicationContext 中来,他提供了 FileSystemResource 来完成从文件系统得到配置文件的资源定义。这样,就可以从文件系统路径上对 IOC 配置文件进行加载 - 当然我们可以按照这个逻辑从任何地方加载,在 Spring 中我们看到它提供的各种资源抽象,比如 ClassPathResource , URLResource ,FileSystemResource 等来供我们使用。上面我们看到的是定位 Resource 的一个过程,而这只是加载过程的一 部分 - 我们回到 AbstractBeanDefinitionReaderz 中的 loadDefinitions(resource) 来看看得到代表 bean 文 件的资源定义以后的载入过程 , 默认的我们使用 XmlBeanDefinitionReader返回
本站支持 pay for your wishes
相关推荐
3、源码分析-IOC容器的初始化 4、源码分析-IOC容器的依赖注入 5、源码分析-IOC容器的高级特性 三阶段 Spring AOP的涉及原理及具体实践 SpringJDBC的涉及原理及二次开发 SpringMVC框架设计原理及手写实现 四阶段 ...
本文深入探讨了Spring框架中IoC容器的源码机制,涵盖了容器的初始化、Bean工厂的实例化、Bean定义的读取及Spring Bean的生命周期管理。通过精细的分析,本文揭示了AnnotationConfigApplicationContext的实例化过程,...
为Spring提供了基础的Web功能支持,主要建立于核心容器之上,通过Servlet或者Listeners来初始化IOC容器; spring-webmvc: 主要提供对SpringMVC的支持,例如SpringMVC中的DispatcherServlet就是该模块中提供的; ...
本文深入探讨了Spring IoC容器的加载过程及其源码实现,揭示了Spring中最为根本的概念之一。这包括从AnnotationConfigApplicationContext的实例化开始,到DefaultListableBeanFactory工厂的建立,再到...
1、通过分析 Spring 源码,深刻掌握核心原理和设计思想 2、通过本课的学习,完全掌握 SpringIOC 容器的初始化细节,并手绘时序图 3、掌握看源码不
简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理...
整个视频课程将由浅入深,介绍spring5源码的构建、spring5IOC容器的初始化过程、bean的声明周期过程、spring BeanFactoryPostporcessor并且结合原理给出当前流行的应用框架如何利用spring的源码知识写出优雅的代码,...
包括内容:Spring体系结构、Spring重要接口讲解(BeanFactory继承体系、BeanDefinition继承体系、ApplicationContext继承体系)、IOC/DI(容器初始化流源码分析)、AOP原理(解析流程,代理流程,执行流程)、事务...
java进阶源码分析专题常用设计模式线程与并发锁的使用深度理解synchronized、volatile、cas手写ASQSpring5IOC容器设计原理及高级特性AOP设计原理FactoryBean与BeanFactorySpring事务处理机制Spring JDK动态代理...
8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...
8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...
8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...
8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...