Spring IoC 源码系列(一)BeanDefinition 初始化与注册

一、BeanDefinition

1.1 什么是 BeanDefinition

在一般的 Spring 项目中,主要通过 XML 的方式配置 bean,而 BeanDefinition 就是 XML 配置属性的载体,XML 文件首先会被转化成 Document 对象,通过解析 Document,把 XML 中 <bean /> 标签转化成 BeanDefinition 供 IoC 容器创建 bean 时使用。

我们可以来做个测试。

    <bean id="typeMismatch" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
        <property name="name"><value>typeMismatch</value></property>
        <property name="age"><value>34x</value></property>
        <property name="spouse"><ref bean="rod"/></property>
    </bean>

下面是 debug 后抓到的 BeanDefinition 属性。

1.2 BeanDefinition 初始化流程图

在这里插入图片描述

二、源码分析

Debug 测试类入口:org.springframework.beans.factory.xml.XmlBeanDefinitionReaderTests#withOpenInputStream

下面只是把核心流程拿出来作了分析,一些细节知识点,有兴趣的可以自行了解。

测试代码如下

    @Test(expected = BeanDefinitionStoreException.class)
    public void withOpenInputStream() {
   
        /**
         * 注意这里初始化的是 SimpleBeanDefinitionRegistry 不具备 BeanFactory 功能
         * 仅仅用来注册 BeanDefinition,不能用来创建 bean
         */
        SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
        Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml"));
        new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
    }

loadBeanDefinitions 源码如下

    @Override
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   
        // 使用 EncodedResource 包装 Resource,EncodedResource 可以指定字符集编码
        return loadBeanDefinitions(new EncodedResource(resource));
    }

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

        // 获取已经加载过的资源集合
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
   
            // 初始化 currentResources
            currentResources = new HashSet<>(4);
            // 设置初始化的 currentResources
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
   
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
   
            // 根据 Resource 获取输入流
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
   
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
   
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                // 核心逻辑,加载 bean 资源
                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()) {
   
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值