美文网首页
Spring5IOC容器解析——XML配置的资源定位、加载、解析

Spring5IOC容器解析——XML配置的资源定位、加载、解析

作者: 小波同学 | 来源:发表于2020-06-10 00:03 被阅读0次

从FileSystemXmlApplicationContext开始

ApplicationContext applicationContext = new FileSystemXmlApplicationContext(xmlPath);

由上面的入口进入到构造方法中

public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
    this(new String[] {configLocation}, true, null);
}

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

    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        //从此处开始IOC容器的初始化
        refresh();
    }
}

设置好配置资源的路径之后,就会调用refresh()方法进行容器的初始化

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {

    /**
     * 加载或刷新一个持久化的配置,可能是XML文件、属性文件或关系数据库模式。
     * 由于这是一种启动方法,如果失败,应该销毁已经创建的单例,以避免悬空资源。
     * 换句话说,在调用该方法之后,要么全部实例化,要么完全不实例化。
     * @throws 如果bean工厂无法初始化,则抛出 BeansException 异常
     * @throws 如果已经初始化且不支持多次刷新,则会抛出 IllegalStateException 异常
     */
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        // 给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或者销毁的操作
        synchronized (this.startupShutdownMonitor) {
            // 调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识,具体方法
            prepareRefresh();

            //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
            //子类的refreshBeanFactory()方法启动,里面有抽象方法
            //针对xml配置,最终创建内部容器,该容器负责 Bean 的创建与管理,此步会进行BeanDefinition的注册
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 注册一些容器中需要的系统Bean.例如classloader,beanfactoryPostProcessor等
            prepareBeanFactory(beanFactory);

            try {
                //允许容器的子类去注册postProcessor  ,钩子方法
                postProcessBeanFactory(beanFactory);

                // 激活在容器中注册为bean的BeanFactoryPostProcessors
                //对于注解容器,org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
                //方法扫描应用中所有BeanDefinition并注册到容器之中
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册拦截bean创建过程的BeanPostProcessor
                registerBeanPostProcessors(beanFactory);

                // 找到“messageSource”的Bean提供给ApplicationContext使用,
                // 使得ApplicationContext具有国际化能力。
                initMessageSource();

                // 初始化ApplicationEventMulticaster该类作为事件发布者,
                // 可以存储所有事件监听者信息,并根据不同的事件,通知不同的事件监听者。
                initApplicationEventMulticaster();

                // 预留给 AbstractApplicationContext 的子类用于初始化其他特殊的 bean,
                // 该方法需要在所有单例 bean 初始化之前调用
                // 比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource)
                onRefresh();

                // 注册监听器(检查监听器的bean并注册它们)
                registerListeners();

                //设置自定义的类型转化器ConversionService,
                // 设置自定义AOP相关的类LoadTimeWeaverAware,
                // 清除临时的ClassLoader
                // ,实例化所有的类(懒加载的类除外)
                finishBeanFactoryInitialization(beanFactory);

                // 初始化容器的生命周期事件处理器,(默认使用DefaultLifecycleProcessor),调用扩展了SmartLifecycle接口的start方法
                // 当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)
                // 并发布容器刷新完毕事件ContextRefreshedEvent给对应的事件监听者
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                //销毁已创建的Bean
                destroyBeans();

                // Reset 'active' flag.
                //取消refresh操作,重置容器的同步标识
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // 重置Spring内核中的共用的缓存,因为我们可能再也不需要单例bean的元数据了……
                resetCommonCaches();
            }
        }
    }
}

AbstractApplicationContext的refresh()方法是容器刷新都会执行的方法,在refresh()方法里面配置的解析逻辑都在obtainFreshBeanFactory()方法中进行。

跟进obtainFreshBeanFactory方法

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //调用子类容器的refreshBeanFactory()刷新子类容器
    refreshBeanFactory();
    return getBeanFactory();
}

跟进refreshBeanFactory()方法,该方法由其子类AbstractRefreshableApplicationContext提供

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        //如果已经有容器,销毁容器中的bean,关闭容器
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            //创建容器
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            //对容器进行定制化,默认主要设置是否允许BeanDefinition的重复注册,
            // Bean之间是否允许循环引用等,此外还可以设置启动参数,开启注解的自动装配等
            customizeBeanFactory(beanFactory);
            //加载BeanDefinition,for xml,使用了委派模式
            loadBeanDefinitions(beanFactory);
            //将 BeanFactory 设置为 Spring 容器的内部 BeanFactory
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
}

xml方式加载BeanDefinition,跟进loadBeanDefinitions(beanFactory)

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        // 1、为给定的BeanFactory创建一个新的XmlBeanDefinitionReader
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        // 2、设置 BeanDefinitionReader 的相关属性
        // 2.1.设置 Environment,即环境,与容器的环境一致
        beanDefinitionReader.setEnvironment(this.getEnvironment());

        // 2.2.设置 ResourceLoader,即资源加载器,因为容器实现了该接口,具体加载资源的功能
        beanDefinitionReader.setResourceLoader(this);
        // 2.3.设置 EntityResolver,即实体解析器,这里用于解析资源加载器加载的资源内容
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        // 3.初始化 BeanDefinitionReader ,空方法,允许子类提供阅读器的自定义初始化
        // 钩子方法,允许子类在加载bean definition之前进一步设置XmlBeanDefinitionReader
        // ->比如,更改XmlBeanDefinitionReader自己提供的DocumentLoader
        // 或者BeanDefinitionDocumentReader等默认对象
        initBeanDefinitionReader(beanDefinitionReader);
        // 4.通过 BeanDefinitionReader 加载 Bean
        loadBeanDefinitions(beanDefinitionReader);
    }
}

观察代码,该方法的主要目的是创建了BeanDefinitionReader ,并由它去加载 Bean。其过程如下:

  • 创建 BeanDefinitionReader
  • 设置 BeanDefinitionReader 的相关属性
  • 初始化 BeanDefinitionReader
  • 通过 BeanDefinitionReader 加载 Bean

通过 BeanDefinitionReader 加载 Bean

在创建完 BeanDefinitionReader 后,则就需要通过它来 加载 Bean,接着跟进loadBeanDefinitions(beanDefinitionReader)方法

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }
}

接着跟进reader.loadBeanDefinitions(configLocations)

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {

    @Override
    public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int count = 0;
        for (String location : locations) {
            count += loadBeanDefinitions(location);
        }
        return count;
    }
}

根据locations逐个调用loadBeanDefinitions(location)加载

通过 Location 加载 Bean

加载的 Bean 的责任被交给了 BeanDefinitionReader ,下面来看看该类的 loadBeanDefinitions 方法。在跟进loadBeanDefinitions(String location)方法

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {

    @Override
    public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(location, null);
    }

    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        // 1.取得资源加载器,即容器本身
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        // 判断资源加载器类型
        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            // 说明该 ResourceLoader 可以基于路径加载多个资源
            try {
                // 2.加载资源
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                // 3.通过 Resource 加载 Bean
                int count = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    Collections.addAll(actualResources, resources);
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
                }
                return count;
            }
            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);
            int count = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
            }
            return count;
        }
    }
}

该方法的工作流程:

  • 取得资源加载器
  • 加载资源,通过 location 利用 ResourcePatternResolver加载
  • 通过 Resource 加载 Bean

接着在跟进loadBeanDefinitions(resources)方法

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {

    @Override
    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int count = 0;
        for (Resource resource : resources) {
            count += loadBeanDefinitions(resource);
        }
        return count;
    }
}

通过 Resource 加载 Bean

在得到资源(Resource)后,该方法对它进行了封装,使其变成一个 EncodedResource 对象。

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
    @Override
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        // EncodedResource 表示编码类型的资源
        return loadBeanDefinitions(new EncodedResource(resource));
    }
}

通过 EncodedResource 加载 Bean

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    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);
        }

        // 1.取得[已加载的资源]的集合,用于存在已加载的资源。空,则创建。
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        // 2.将当前资源加入集合
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        // 3.将资源转换成流
        try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
            //5.通过流创建 InputSource ,并设置编码
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            //6.调用同类方法,通过 InputSource 加载 Bean
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            // 移除已完成解析的资源
            currentResources.remove(encodedResource);
            // 集合为空,则一并删除
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }
}

加载步骤:

  • 1、取得已加载的资源集合
  • 2、将当前资源添加到集合
  • 3、将资源转换成流
  • 4、通过流创建 InputSource ,并设置编码
  • 5、通过 InputSource 加载 Bean

通过 InputSource 加载 Bean

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {

        try {
            // 1.解析 XML 文件
            //创建Document对象,XML的文档对象,就是dom树
            // 使用这个Document可以获取XML文件中的节点并且创建节点
            // SAX XML
            //将InputSource转换为DOM对象,解析过程由documentLoader实现
            Document doc = doLoadDocument(inputSource, resource);
            // 2.注册 Bean
            //解析dom树,即解析出一个个属性,将其保存到BeanDefinition当中
            //并向容器注册BeanDefinition
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }
}

解析并注册 BeanDefinitions

将文件装换为Document以后,接下来的提取以及注册Bean就是我们的重头戏。
上一步中 XmlBeanDefinitionReader 已经取得了 XML 的 Document 对象,完成了资源的解析过程。
下一步就是 Bean 的注册过程。

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //创建BeanDefinitionDocumentReader,这个是实际从XML的DOM树中读取BeanDefiniton
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        //获取注册表beanDefinitionMap的在本次加载前的BeanDefinition数量
        int countBefore = getRegistry().getBeanDefinitionCount();
        //加载并注册
        //这里使用到了单一职责原则,将逻辑处理委托给单一的类进行处理,这个逻辑处理类就是 BeanDefinitionDocumentReader 对象
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        //本次加载注册后容器里BeanDefinition的数量减去先前的,即本次加载的BeanDefinition数量
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
}

继续深入registerBeanDefinitions方法:

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        doRegisterBeanDefinitions(doc.getDocumentElement());
    }
}

继续深入doRegisterBeanDefinitions方法:doRegisterBeanDefinitions算开始真正解析XML文件了。

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        //BeanDefinition解析委托类
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);
        //判断这个根节点是否是默认的命名空间
        //底层就是判断这个根节点的NamespaceUrl=="http://www.springframework.org/schema/beans"
        if (this.delegate.isDefaultNamespace(root)) {
            //获取这个profile属性的值,表示剖面,用于设置环境
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                //根据分隔符换换成数组
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                //判断这个切面是否是激活的环境,如果不是直接返回,表示这个配置文件不是当前运行环境的配置文件
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }
        //在解析xml之前做的准备工作,其实什么也没做
        //空代码留给子类去实现 模板设计模式 继承 DefaultBeanDefinitionDocumentReader 的子类在XML解析前做一些处理,可以实现此方法
        preProcessXml(root);
        //调用这个方法,解析
        parseBeanDefinitions(root, this.delegate);
        //后续处理的
        //空代码留给子类去实现 模板设计模式 继承 DefaultBeanDefinitionDocumentReader 的子类在XML解析后做一些处理,可以实现此方法
        postProcessXml(root);

        this.delegate = parent;
    }
}

继续深入parseBeanDefinitions(root, this.delegate),进入到真正的解析逻辑里面对BeanDefinition进行解析

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //如果是默认的命名空间
        if (delegate.isDefaultNamespace(root)) {
            //获取根节点下的所有子节点
            NodeList nl = root.getChildNodes();
            //遍历所有的子节点
            for (int i = 0; i < nl.getLength(); i++) {
                //取出节点
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    //Bean定义的Document对象使用了Spring默认的XML命名空间,如http://www.springframework.org/schema/beans
                    if (delegate.isDefaultNamespace(ele)) {
                        //若是则按照spring原有的逻辑进行解析
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        //否则使用扩展的自定义代理类进行解析
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            //使用扩展的自定义代理类进行解析
            delegate.parseCustomElement(root);
        }
    }
}

继续深入parseDefaultElement(ele, delegate),此方法会完成对标签的解析

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        //如果元素节点是<Import>导入元素,进行导入解析
        //<import resource="classpath:applicationContext-datasource.xml" />
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        //如果元素节点是<Alias>别名元素,进行别名解析
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素,
        //按照Spring的Bean规则解析元素
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
        }
        //解析beans,递归调用doRegisterBeanDefinitions
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }
}

继续深入processBeanDefinition(ele, delegate),此方法会真正解析出BeanDefinition

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类
        //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                //向Spring IOC容器注册解析得到的BeanDefinition,这是BeanDefinition向IOC容器注册的入口
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            // 在完成BeanDefinition注册之后,往容器发送注册完成的事件
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
}
  • 由BeanDefinitionParserDelegate将解析出来的BeanDefinition封装到BeanDefinitionHolder中。
  • 由BeanDefinitionReaderUtils的registerBeanDefinition方法将BeanDefinition注册到Spring IOC容器中。
  • 最终调用DefaultListableBeanFactory类的registerBeanDefinition方法将beanDefinition注册到beanDefinitionMap中。

以上便是资源定位、加载、解析、注册的整个流程。


XML配置方式的BeanDefinition注册流程:

  • 1、在FileSystemXmlApplicationContext的构造函数中设置配置资源的路径,接着调用refresh()方法进行容器的初始化。
  • 2、refresh方法中的obtainFreshBeanFactory()方法进行配置的解析逻辑。
  • 3、调用子类容器的refreshBeanFactory()刷新子类容器。
  • 4、在AbstractRefreshableApplicationContext类的refreshBeanFactory方法中创建DefaultListableBeanFactory实例。
  • 5、将DefaultListableBeanFactory实例作为参数传入到loadBeanDefinitions方法中。
  • 6、在loadBeanDefinitions方法中通过DefaultListableBeanFactory创建XmlBeanDefinitionReader实例。
  • 7、在loadBeanDefinitions方法中设置ResourceLoader用于加载资源,(即容器实例,容器实现了ResourceLoader接口)
  • 8、通过BeanDefinitionReader加载Bean资源。
  • 9、通过ResourcePatternResolver来加载资源,并通过EncodedResource包装资源实例。
  • 10、XmlBeanDefinitionReader类的doLoadBeanDefinitions通过 InputSource加载Bean。
  • 11、XmlBeanDefinitionReader类的doLoadDocument方法将xml解析成Document对象。
  • 12、XmlBeanDefinitionReader类的registerBeanDefinitions方法创建BeanDefinitionDocumentReader实例。
  • 13、在BeanDefinitionDocumentReader类的registerBeanDefinitions方法中,从Document对象中解析并注册BeanDefiniton。
  • 14、DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions方法通过参数BeanDefinitionParserDelegate解析BeanDefinition。
  • 15、DefaultBeanDefinitionDocumentReader类的parseDefaultElement按照spring原有的逻辑进行解析。
  • 16、通过BeanDefinitionParserDelegate的parseBeanDefinitionElement解析出包含了BeanDefinition实例的BeanDefinitionHolder包装实例。
  • 17、通过BeanDefinitionReaderUtils类的registerBeanDefinition方法将BeanDefinition实例注册到容器中,如果BeanDefinition是单例的化,之前已经注册过了的,就需要清空之前的注册信息。
  • 18、使用beanName做唯一标识注册到DefaultListableBeanFactory类中的beanDefinitionMap中,有别名注册别名。

参考:
https://www.cnblogs.com/moxiaotao/p/9349536.html

https://www.cnblogs.com/histlyb/p/8976635.html

相关文章

网友评论

      本文标题:Spring5IOC容器解析——XML配置的资源定位、加载、解析

      本文链接:https://www.haomeiwen.com/subject/sbsjtktx.html