在第二节中我们销毁了老的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
相关推荐
### Spring源码分析_Spring_IOC:深入理解Spring的IOC容器机制 #### 基本概念与核心作用 在探讨Spring框架的核心组件之一——IOC(Inversion of Control,控制反转)容器之前,首先需要理解它在Spring框架中的角色...
3、源码分析-IOC容器的初始化 4、源码分析-IOC容器的依赖注入 5、源码分析-IOC容器的高级特性 三阶段 Spring AOP的涉及原理及具体实践 SpringJDBC的涉及原理及二次开发 SpringMVC框架设计原理及手写实现 四阶段 ...
Spring 框架系列(7)- Spring IOC 实现原理详解之 IOC 初始化流程 本文将详细解释 Spring 框架中的 IOC...IOC 容器的初始化流程是 Spring 框架中的关键部分,用于将资源配置文件中的信息加载到 IOC 容器中。
《Spring IOC容器实现分析》 在Java开发领域,Spring框架无疑是使用最为广泛的轻量级框架之一,其中的核心组件就是IOC(Inversion of Control)容器。本文将深入剖析Spring的IOC容器,理解其工作原理和重要功能,以...
根据提供的文件信息,本次解读将围绕Spring框架的核心概念与源码分析进行展开。Spring框架作为Java企业级开发中不可或缺的一部分,其源码的学习对于深入理解框架机制、提高开发效率具有重要意义。下面,我们将从以下...
通过分析BeanFactory,我们可以了解对象的创建、初始化和依赖注入过程。 - **AOP**:面向切面编程允许我们定义横切关注点,如日志记录、事务管理,然后将其模块化为可重用的组件。 - **Data Access/...
文档可能将深入探讨Spring IoC容器初始化、Bean生命周期管理、依赖注入等关键概念,并以2021年的开源版本为背景进行分析。 从提供的部分文档内容来看,我们可以提炼出以下几个知识点: 1. **BeanFactory与...
Spring Core负责基础的IoC(Inversion of Control)容器,Spring Beans则实现了Bean的生命周期管理和配置,Spring Context则是基于Core之上构建的,提供了一个应用上下文,可以管理Bean并与其他Spring模块集成。...
5. **Bean管理**:最后,容器会管理Bean的生命周期,包括初始化、使用和销毁。 在实际开发中,Spring使用了更加高效和灵活的方式来实现这些功能,比如使用`ApplicationContext`接口作为IOC容器的入口,以及`...
1. **ApplicationContext**:这是Spring的核心接口,负责初始化、加载配置文件,管理Bean的生命周期。源码中可以看到它是如何解析XML或Java配置,创建并管理Bean的。 2. **BeanFactory**:作为ApplicationContext的...
2. **Spring Beans**:实现了IoC容器,通过XML或注解方式配置bean,并负责bean的初始化、装配和销毁。 3. **Spring AOP**:面向切面编程模块,允许定义方法拦截器和切入点,实现代码的解耦和模块化。 4. **Spring ...
1. **初始化流程**:从`org.springframework.context.support.ClassPathXmlApplicationContext`或`org.springframework.web.context.ContextLoader`开始,理解如何加载配置并创建Bean定义。 2. **依赖注入**:研究`...
通过阅读和学习这些源码,开发者可以了解到Spring如何实现IoC容器、AOP代理、事件机制、任务调度等多个关键功能。同时,这也有助于开发者更好地理解和使用Spring提供的API,以及在实际项目中如何定制和扩展Spring。 ...
在深入探讨Spring框架的核心组件和工作...在分析或运行Spring源码时,确保正确引入这两个库是确保项目正常运行的关键。通过深入了解这些工具库,开发者可以更好地理解和运用Spring框架,从而提高开发效率和应用性能。
IoC容器是Spring框架的心脏,它负责管理对象的生命周期和依赖关系,使得开发者能够实现松耦合和高可测试性的应用程序。 首先,我们来理解什么是IoC。IoC,也被称为依赖注入(Dependency Injection),是一种设计...
通过XML配置文件或Java注解,我们可以定义bean的创建、初始化和销毁过程,实现依赖注入,从而降低代码的耦合度。 2. AOP:Spring的AOP模块允许开发者定义横切关注点,如日志记录、事务管理等,将这些关注点与业务...
通过配置文件或者注解,开发者可以定义对象及其依赖关系,Spring容器会自动管理这些对象的生命周期,包括实例化、初始化、装配和销毁。 **Bean** 在Spring中,业务逻辑的组件被称为Bean。Bean是Spring容器管理的...
本文将基于Spring 2.0版本的源码,深入分析Spring IOC容器的内部实现机制,帮助读者更好地理解和使用这一强大的工具。 #### 二、核心概念与术语 在深入探讨Spring IOC容器之前,我们首先需要了解几个核心的概念: ...
《简易Spring-ioc详解》 在Java开发领域,Spring框架以其强大的功能和广泛的应用而备受开发者喜爱。...此外,掌握这些核心概念后,无论是使用Spring框架还是其他类似的IoC容器,都将更加得心应手。