Web时代-IOC容器初始化源码解析resource的定位

252 阅读3分钟

本文正式的对Ioc容器初始化一探究竟,我们可根据上篇的流程图以起对照着看Ioc容器是如何初始化的。

IOC容器的初始化(以Xml形式的Ioc初始化)

在看具体的容器初始化先看下重要的BeanDefinition的类图

图片

6eD13Q.png

BeanDefinition是配置文件元素标签在容器中内部表示形式。

  • RootBeanDefinition可以单独作为一个BeanDefinition,也可以作为其他BeanDefinition的父类。但是他不能作为其他BeanDefinition的子类

  • ChildBeanDefinition相当于一个子类,不可以单独存在,必须要依赖一个父BeanDetintion

  • GenericBeanDefinition可以替代RootBeanDefinitionChildBeanDefinition

  • AnnotatedGenericBeanDefinition处理@Configuration注解

  • ConfigurationClassBeanDefinition处理@Bean注解

  • ScannedGenericBeanDefinition处理@Component注解

IoC容器的初始化包括BeanDefinition的Resouce定位载入注册这三个基本的过程

BeanDefinition描述和定义了创建一个Bean需要的所有信息,属性,构造函数参数以及访问它们的方法。还有其他一些信息,比如这些定义来源自哪个类等等信息

Resouce定位: BeanDefinition的资源定位由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用提供了统一接口。比如说,在文件系统中的Bean定义信息可以使用FileSystemResource来进行抽象;在类路径中可以使用前面提到的ClassPathResource来使用,等等。这个过程类似于容器寻找数据的过程,就像用水桶装水先要把水找到一样

BeanDefinition的载入: 第二个关键的部分是BeanDefinition的载入,该载入过程把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition,总地说来,这个BeanDefinition定义了一系列的数据来使得IoC容器能够方便地对POJO对象也就是Spring的Bean进行管理。即BeanDefinition就是Spring的领域对象模型

BeanDefinition的注册: 第三个过程是向IoC容器注册这些BeanDefinition的过程。这个过程是通过调用BeanDefinitionRegistry接口的实现来完成的,这个注册过程把载入过程中解析得到的BeanDefinition向IoC容器进行注册。可以看到,在IoC容器内部,是通过使用一个HashMap来持有这些BeanDefinition数据的。

BeanDefinition的Resource定位

Resource定位这个过程就是我们所看到的寻找bean定义的资源配置文件,找到”applicationContext.xml“以及其他的配置文件信息。

这时我们可以使用的是ClassPathResource,意味着Spring会在类路径中寻找以文件形式存在的BeanDefinition信息。

ClassPathResource res = new ClassPathResource("beans.xml") 使用这个代码不能让DefaultListableBeanFactory.

这个过程是使用的ApplicationContext的实现类ClassPathXmlApplicationContext,FileSystemXmlApplicationContext,WebApplicationContext 通过这些类去定位到Resource对象。

以ClassPathXmlApplicationContext获取bean为例深入源码分析
ClassPathXmlApplicationContext  context = new ClassPathXmlApplicationContext("bean.xml");

当程序通过new的时候会进行调用其构造方法,在构造方法内进行资源加载,主要看构造方法内的setConfigLocations(configLocations) 进行资源定位

public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {

        super(parent);
        // 资源定位
        setConfigLocations(configLocations);
        // 载入BeanDefinition的入口
        if (refresh) {
            refresh();
        }
    }

资源定位集中在抽象类AbstractRefreshableConfigApplicationContext的setConfigurations()方法内我们具体的看下:在这个方法内是先进行断言这个位置是否为null.在这类中初始了一个String[] configLocations数组.将解析后的路径填充到这个数组中。

/**
* 设置上下文的配置,如果未配置则 可以进行默认配置
*
**/
public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            // 断言是否为空路径
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {
                // resolvePath为同一类中将字符串解析路径的方法
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }
/**
* 路径的解析
*/
protected String resolvePath(String path) {
    return getEnvironment().resolveRequiredPlaceholders(path);
}
/**
* 获取路径
*/
@Override
public ConfigurableEnvironment getEnvironment() {
    // 环境为null则进行创建环境
    if (this.environment == null) {
        this.environment = createEnvironment();
    }
    // 否者返回档期那的环境
    return this.environment;
}
/**
* 创建并返回一个环境
**/
protected ConfigurableEnvironment createEnvironment() {
    return new StandardEnvironment();
}
/**
*这个时候创建了一个标准的环境。可以看到resolvePath()方法来自AbstractEnvironment类中
*
**/
public class StandardEnvironment extends org.springframework.core.env.AbstractEnvironment {
    public static final java.lang.String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
    public static final java.lang.String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";

    public StandardEnvironment() /* compiled code */ }

    protected void customizePropertySources(org.springframework.core.env.MutablePropertySources propertySources) /* compiled code */ }
}

经过上面的步骤这样就完成了Resource的定位。

本文使用 文章同步助手 同步