Spring如何j将xml配置映射为BeanDefinition

发布时间 2023-12-17 15:51:31作者: 残城碎梦

Spring的常用配置文件是applicationContext.xml文件,最简单的,一般我们都会添加这样的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.harvey.demo.*"></context:component-scan>

</beans>

Spring是根据BeanDefinition来创建Bean对象,BeanDefinition就是Spring中表示Bean定义。BeanDefinition用来存储Bean的相关信息,主要包括:Bean的属性、是否单例、延迟加载、Bean的名称、构造方法等。

那Spring是如何找到所有的目标类创建对象的BeanDefinition的呢?

入口是AbstractApplicationContext的refresh方法

AbstractApplicationContext#refresh{

    // Prepare this context for refreshing.
    prepareRefresh();

    // Step2:调用子类覆盖的方法obtoinFreshBeanFactory(),创建新的BeanFactory,默认实现是DefaultListableBeanFactory
    // 解析xml,生成BeanDefinition并注册到 BeanDefinitionRegistry
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);

    // Allows post-processing of the bean factory in context subclasses.
    postProcessBeanFactory(beanFactory);

    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);

    // Register bean processors that intercept bean creation.
    registerBeanPostProcessors(beanFactory);

    // Initialize message source for this context.
    initMessageSource();

    // Initialize event multicaster for this context.
    initApplicationEventMulticaster();

    // Initialize other special beans in specific context subclasses.
    onRefresh();

    // Check for listener beans and register them.
    registerListeners();

    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);

    // Last step: publish corresponding event.
    finishRefresh();

}

在obtainFreshBeanFactory方法中一共是两个方法

  • refreshBeanFactory:初始化BeanFactory
  • getBeanFactory:返回实例化的BeanFactory
ConfigurableListableBeanFactory#obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

走到refreshBeanFactory()方法内部,核心方法loadBeanDefinitions(),这个方法是读取xml文件读取bean的定义。最后赋值到该类的BeanFactory中。

AbstractRefreshableApplicationContext#refreshBeanFactory{
    //如果已经存在BeanFactory,则先销毁先前的BeanFactory,关闭连接以释放资源
    if (hasBeanFactory()) {
        //销毁先前的BeanFactory
        destroyBeans();
        //关闭连接
        closeBeanFactory();
    }
    try {
        //创建一个新的BeanFactory,在这里使用DefaultListableBeanFactory作为BeanFactory的默认实现类
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        //设置从ID,用于 BeanFactory 的序列化和反序列化
        beanFactory.setSerializationId(getId());
        //调用子类的customizeBeanFactory方法,用于在创建新的BeanFactony后,对BeanFactory进行附加的自定义设置
        customizeBeanFactory(beanFactory);
        /**    
         * 【重点】加载Bean定义,这个bean definition 是通过XmlBeanDefinitionReader来读取Spring的配置文件(通常为XL格式的〉,得到Bean定义实现类AbstractXmlApplicationContext    
         */
        loadBeanDefinitions(beanFactory);
        //将当前BeanFactory实例赋值给该类实例的beanFactory变量中
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        //如果在解析Bean定义源时遇到I/0错误,则抛出ApplicationContextException异常
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

 

 点击查看这个类下的实现方法。

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // 为beanFactory创建XmlBeanDefinitionReader对象
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    //用当前 ApplicationContext的环境来配置 BeanDefinition读取器
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    //初始化 BeanDefinition 读取器,让子类可以对其进行自定义初始化(留一个可扩展的接口)
    initBeanDefinitionReader(beanDefinitionReader);
    /**关键方法:读取 BeanDefinition并向 BeanFactory注册*/
    loadBeanDefinitions(beanDefinitionReader);
}

然后走到loadBeanDefinitions(),还是调用loadBeanDefinitions()方法。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        //将每一个Resource的 BeanDefinition 读取并注册到BeanDefinitionRegistry 中
        reader.loadBeanDefinitions(configResources);
    }
    //获取要加载的配置文件路径,即ClassPath下的XML配置
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        /**
         * 关键方法:根据路径加载配置文件中的 BeanDefinition并注册到 BeanFactory 中
         */
        reader.loadBeanDefinitions(configLocations);
    }
}

 

 

 

@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
    Assert.notNull(resources, "Resource array must not be null");
    int counter = 0;
    for (Resource resource : resources) {
        /**入口,实现类XmlBeanDefinitionReader.loadBeanDefinitions*/
        counter += loadBeanDefinitions(resource);
    }
    return counter;
}
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 {
        //把XML读取的文件流,解析成InputSource对象
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            /**入口,spring框架里面真正干活的方法名 doXXX*/
            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();
        }
    }
}

到了这个方法,才开始执行真正的逻辑,通过读取资源载入Bean定义信息。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException {
    try {
        //读取XML配置,把配置文件转成Document对象
        Document doc = doLoadDocument(inputSource, resource);
        /**根据解析得到的Document对象,将其中的 Bean配置信息注册到BeanFactory 中*/
        return registerBeanDefinitions(doc, resource);
    }
    catch (BeanDefinitionStoreException ex) {
        throw ex;
    }
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //创建 BeanDefinitionDocumentReader对象,用于读取文档转化成的 Element
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    //记录当前注册的 Bean数量
    int countBefore = getRegistry().getBeanDefinitionCount();
    /**
     * 通过BeanDefinitionDocumentReader的实现来对所提供的Document的BeanDefinition进行解析
     * 关键方法:registerBeanDefinitions
     */
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    //计算当前实际注册的Bean数量
    return getRegistry().getBeanDefinitionCount() - countBefore;
}
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    logger.debug("Loading bean definitions");
    Element root = doc.getDocumentElement();
    doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                }
                return;
            }
        }
    }
    //预处理XNL元素,例如在XML解析之前可以修改XML DOM树,空实现,给子类定义
    preProcessXml(root);
    /**关键入口:解析Bean定义并注册 Bean 到 BeanFactory 容器中*/
    parseBeanDefinitions(root, this.delegate);
    //后处理XML元素,例如解析后的 Bean定义可能需要改变XNL DOM树等,空实现,给子类定义
    postProcessXml(root);
    // 恢复到原先的的 BeanDefinitionParserDelegate 委托对象
    this.delegate = parent;
}
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) {
                //如果子节点也是元素节点,并且也使用了默认命名空间,则通过默认方式解析元素
                //默认的命名空间是:http://www.springframework.org/schema/beans
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    //解析bean元素信息
                    parseDefaultElement(ele, delegate);
                }
                else {
                    //如果没有指定默认命名空间,也通过自定义方式解析元素
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}

解析xml节点分为两种情况:

  • 解析默认命名空间下的元素,即http://www.springframework.org/schema/beans
  • 解析非默认命名空间下的元素

首先我们来看看如何解析默认命名空间下的元素

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    //解析<import>元素
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    //解析<alias>元素
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    //解析<bean>元素
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        //关键方法:bean元素处理
        processBeanDefinition(ele, delegate);
    }
    //解析<beans>元素
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        //递归调用doRegisterBeanDefinitions()方法解析并注册嵌套的<beans>元素
        doRegisterBeanDefinitions(ele);
    }
}

 

 

 

回到前面代码,我们再看看是如何解析非默认命名空间下的元素的

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
    //第一步:获取元素的namespaceUri
    String namespaceUri = getNamespaceURI(ele);
    if (namespaceUri == null) {
        return null;
    }
    //第二步:通过namespaceUri获取对应的NamespaceHandler,
    //例如<context>的命名空间处理器就是ContextNamespaceHandler
    //在这里会实例化NamespaceHandler,并调用其init方法,创建诸多解析器,其中就有component-scan对应的解析器ComponentScanBeanDefinitionParser
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    //第三步:调用NamespaceHandler的parse方法准备开始解析
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
//【NamespaceHandlerSupport】
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
    //根据元素拿到对应的解析器,比如component-scan对应的解析器ComponentScanBeanDefinitionParser
    BeanDefinitionParser parser = findParserForElement(element, parserContext);
    //调用对应解析器的parse方法解析
    return (parser != null ? parser.parse(element, parserContext) : null);
}
//【ComponentScanBeanDefinitionParser】
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
    //获取元素的base-package属性值
    String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
    //处理占位符
    basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
    String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
                                                              ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

    //根据一些自定义配置信息创建扫描器,比如include-filter、exclude-filter等等
    ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
    //找到声明包路径下的组件,并将类信息封装,实例化为BeanDefinitionHolder,并注册到beanDefinitionMap中
    Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
    //注册其他组件,比如一些依赖bean、内部bean
    registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
    return null;
}

 整一个创建的流程,就走完啦,从解析xml,到封装成BeanDefinition,最后放入map中的核心流程。