Spring容器的初始化流程

本文详细剖析了Spring容器从创建BeanFactory、加载BeanDefinition到创建Bean的整个流程。首先,从refresh方法的obtainFreshBeanFactory开始,创建DefaultListableBeanFactory作为核心容器。接着,通过loadBeanDefinitions加载BeanDefinition,解析XML配置文件并注册BeanDefinition。最后,讨论了预实例化单例Bean的过程,关键在于doCreateBean方法,这是Bean创建的核心步骤。
摘要由CSDN通过智能技术生成

一、创建BeanFactory流程

1、流程入口

创建BeanFactory的流程是从refresh方法的第二步开始的,通过调用obtainFreshBeanFactory方法完成流程。

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

2、流程分析

创建BeanFactory的流程是从第二步开始的,调用AbstractApplicationContext类中的obtainFreshBeanFactory方法:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   
		// 主要是通过该方法完成IoC容器的刷新
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
   
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
}

调用AbstractRefreshableApplicationContext中的refreshBeanFactory方法:

protected final void refreshBeanFactory() throws BeansException {
   
    // 如果之前有IoC容器,则销毁
    if (hasBeanFactory()) {
   
        destroyBeans();
        closeBeanFactory();
    }
    try {
   
        // 创建IoC容器,也就是DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        // 设置工厂的属性:是否允许BeanDefinition覆盖和是否允许循环依赖
        customizeBeanFactory(beanFactory);
        // 调用载入BeanDefinition的方法,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
   
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
   
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

其中调用createBeanFactory方法创建IoC容器。这里创建的是DefaultListableBeanFactory,它是真正用于管理Bean实例及BeanDefeation的工厂。

二、加载BeanDefeation流程

1、流程入口

此流程是从AbstractRefreshableApplicationContext的refreshBeanFactory方法开始的,代码如上所示,通过loadBeanDefinitions(beanFactory)进行BeanDefeation的加载。

 loadBeanDefinitions(beanFactory);

2、流程图

这里的调用较为复杂,可通过下面流程图进行说明:

AbstractRefreshabl AbstractXmlApp XmlBeanDefi loadBeanDefinitions(DefaultListableBeanFactory) loadBeanDefinitions(XmlBeanDefinitionReader) loadBeanDefinitions(Resource) loadBeanDefinitions(EncodedResource) doLoadBeanDefinitions() registerBeanDefinitions() AbstractRefreshabl AbstractXmlApp XmlBeanDefi

3、流程分析

在创建完Ioc容器之后,调用AbstractXmlApplicationContext的loadBeanDefinitions进行beanDefeation的加载,其代码如下:

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   
    // 创建一个BeanDefinition阅读器,通过阅读XML文件,真正完成BeanDefinition的加载和注册
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    initBeanDefinitionReader(beanDefinitionReader);
    // 委托给BeanDefinition阅读器去加载BeanDefinition
    loadBeanDefinitions(beanDefinitionReader);
}

再调用其重载方法loadBeanDefinitions,代码如下:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   
    // 获取资源的定位
    // 这里getConfigResources是一个空实现,真正实现是调用子类的获取资源定位的方法
    // 比如:ClassPathXmlApplicationContext中进行了实现,而FileSystemXmlApplicationContext没有使用该方法
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
   
        // XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
        reader.loadBeanDefinitions(configResources);
    }
    // 如果子类中获取的资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
   
        // XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
        reader.loadBeanDefinitions(configLocations);
    }
}

再调用的方法,代码如下:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   
    // 将读入的XML资源进行特殊编码处理
    return loadBeanDefinitions(new EncodedResource(resource));
}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
   
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if (logger.isInfoEnabled()) {
   
        logger.info("Loading XML bean definitions from " + encodedResource.getResource());
    }

    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    if (currentResources == null) {
   
        currentResources = new HashSet<>(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }
    if (!currentResources.add(encodedResource)) {
   
        throw new BeanDefinitionStoreException(
            "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    }
    try {
   
        // 将资源文件转为InputStream的IO流
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
   
            // 从InputStream中得到XML的解析源
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
   
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            // 这里是具体的读取过程
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
        finally {
   
            inputStream.close();
        }
    }
    catch (IOException ex) {
   
        throw new BeanDefinitionStoreException(
            "IOException parsing XML document from " + encodedResource.getResource(), ex);
    }
    finally {
   
        currentResources.remove(encodedResource);
        if (currentResources.isEmpty()) {
   
            this.resourcesCurrentlyBeingLoaded.remove();
        }
    }
}

具体的读取过程在doLoadBeanDefinitions方法中进行,将读取的beanDefinition信息进行注册:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException {
   
    try {
   
        // 通过DOM4J加载解析XML文件,最终形成Document对象
        Document doc = doLoadDocument(inputSource, resource);
        // 通过对Document对象的操作,完成BeanDefinition的加载和注册工作
        return registerBeanDefinitions(doc, resource);
    }
    //抛出异常。。。
}

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreExc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值