`

spring 源码分析--IOC容器初始化四

阅读更多

在第二节中我们销毁了老的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

1
0
分享到:
评论
1 楼 lixia0417 2016-01-22  
很清晰。

相关推荐

    Spring源码分析_Spring_IOC

    ### Spring源码分析_Spring_IOC:深入理解Spring的IOC容器机制 #### 基本概念与核心作用 在探讨Spring框架的核心组件之一——IOC(Inversion of Control,控制反转)容器之前,首先需要理解它在Spring框架中的角色...

    Spring源码解析4章150页+Spring3.2.4中文注释源码

    3、源码分析-IOC容器的初始化 4、源码分析-IOC容器的依赖注入 5、源码分析-IOC容器的高级特性 三阶段 Spring AOP的涉及原理及具体实践 SpringJDBC的涉及原理及二次开发 SpringMVC框架设计原理及手写实现 四阶段 ...

    Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程.doc

    Spring 框架系列(7)- Spring IOC 实现原理详解之 IOC 初始化流程 本文将详细解释 Spring 框架中的 IOC...IOC 容器的初始化流程是 Spring 框架中的关键部分,用于将资源配置文件中的信息加载到 IOC 容器中。

    Spring IOC容器实现分析.pdf 下载

    《Spring IOC容器实现分析》 在Java开发领域,Spring框架无疑是使用最为广泛的轻量级框架之一,其中的核心组件就是IOC(Inversion of Control)容器。本文将深入剖析Spring的IOC容器,理解其工作原理和重要功能,以...

    spring源码解读-地址.txt

    根据提供的文件信息,本次解读将围绕Spring框架的核心概念与源码分析进行展开。Spring框架作为Java企业级开发中不可或缺的一部分,其源码的学习对于深入理解框架机制、提高开发效率具有重要意义。下面,我们将从以下...

    官方原版源码spring-framework-5.1.13.RELEASE.zip

    通过分析BeanFactory,我们可以了解对象的创建、初始化和依赖注入过程。 - **AOP**:面向切面编程允许我们定义横切关注点,如日志记录、事务管理,然后将其模块化为可重用的组件。 - **Data Access/...

    Spring IoC源码深度剖析开源架构源码2021.pdf

    文档可能将深入探讨Spring IoC容器初始化、Bean生命周期管理、依赖注入等关键概念,并以2021年的开源版本为背景进行分析。 从提供的部分文档内容来看,我们可以提炼出以下几个知识点: 1. **BeanFactory与...

    官方原版源码 spring-framework-5.1.15.RELEASE.zip

    Spring Core负责基础的IoC(Inversion of Control)容器,Spring Beans则实现了Bean的生命周期管理和配置,Spring Context则是基于Core之上构建的,提供了一个应用上下文,可以管理Bean并与其他Spring模块集成。...

    官方原版源码spring-framework-5.1.0.RELEASE.zip

    2. **Spring Beans**:实现了IoC容器,通过XML或注解方式配置bean,并负责bean的初始化、装配和销毁。 3. **Spring AOP**:面向切面编程模块,允许定义方法拦截器和切入点,实现代码的解耦和模块化。 4. **Spring ...

    【框架源码篇 01】Spring源码-手写IOC

    5. **Bean管理**:最后,容器会管理Bean的生命周期,包括初始化、使用和销毁。 在实际开发中,Spring使用了更加高效和灵活的方式来实现这些功能,比如使用`ApplicationContext`接口作为IOC容器的入口,以及`...

    官方原版源码 spring-framework-5.2.9.RELEASE.zip

    1. **ApplicationContext**:这是Spring的核心接口,负责初始化、加载配置文件,管理Bean的生命周期。源码中可以看到它是如何解析XML或Java配置,创建并管理Bean的。 2. **BeanFactory**:作为ApplicationContext的...

    官方原版源码spring-framework-5.0.13.RELEASE.zip

    1. **初始化流程**:从`org.springframework.context.support.ClassPathXmlApplicationContext`或`org.springframework.web.context.ContextLoader`开始,理解如何加载配置并创建Bean定义。 2. **依赖注入**:研究`...

    spring-framework-2.5-rc2-with-dependencies\spring-framework-2.5-rc2\spring-framework-2.5-rc2源代码

    通过阅读和学习这些源码,开发者可以了解到Spring如何实现IoC容器、AOP代理、事件机制、任务调度等多个关键功能。同时,这也有助于开发者更好地理解和使用Spring提供的API,以及在实际项目中如何定制和扩展Spring。 ...

    spring-cglib-repack-3.2.6.jar和spring-objenesis-repack-2.6.jar

    在深入探讨Spring框架的核心组件和工作...在分析或运行Spring源码时,确保正确引入这两个库是确保项目正常运行的关键。通过深入了解这些工具库,开发者可以更好地理解和运用Spring框架,从而提高开发效率和应用性能。

    Spring2.5.6源代码分析(一):IOC容器

    IoC容器是Spring框架的心脏,它负责管理对象的生命周期和依赖关系,使得开发者能够实现松耦合和高可测试性的应用程序。 首先,我们来理解什么是IoC。IoC,也被称为依赖注入(Dependency Injection),是一种设计...

    spring-framework-5.3.29.tar.gz

    通过XML配置文件或Java注解,我们可以定义bean的创建、初始化和销毁过程,实现依赖注入,从而降低代码的耦合度。 2. AOP:Spring的AOP模块允许开发者定义横切关注点,如日志记录、事务管理等,将这些关注点与业务...

    Spring 5.2.9的IOC核心jar包

    通过配置文件或者注解,开发者可以定义对象及其依赖关系,Spring容器会自动管理这些对象的生命周期,包括实例化、初始化、装配和销毁。 **Bean** 在Spring中,业务逻辑的组件被称为Bean。Bean是Spring容器管理的...

    Spring IOC容器实现分析

    本文将基于Spring 2.0版本的源码,深入分析Spring IOC容器的内部实现机制,帮助读者更好地理解和使用这一强大的工具。 #### 二、核心概念与术语 在深入探讨Spring IOC容器之前,我们首先需要了解几个核心的概念: ...

    coco-spring-ioc

    《简易Spring-ioc详解》 在Java开发领域,Spring框架以其强大的功能和广泛的应用而备受开发者喜爱。...此外,掌握这些核心概念后,无论是使用Spring框架还是其他类似的IoC容器,都将更加得心应手。

Global site tag (gtag.js) - Google Analytics