02-Spring配置文件加载

获取IOC容器

加载、解析xml文件,形成GenericBeanDefinition,供后续实例化剩下的所有 Bean 使用。

obtainFreshBeanFactory()

获取IOC容器

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中
    refreshBeanFactory();
    // 返回当前实体的beanFactory属性
    return getBeanFactory();
}

refreshBeanFactory()

刷新IOC容器,此类是一个抽象类,在前面初始化的对象,不同,此类方法执行的不同。这里主要执行的是 AbstractRefreshableApplicationContext中实现的方法。

protected final void refreshBeanFactory() throws BeansException {
    // 如果存在beanFactory,则销毁beanFactory
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 创建DefaultListableBeanFactory对象
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // 为了序列化指定id,可以从id反序列化到beanFactory对象
        beanFactory.setSerializationId(getId());
        // 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
        customizeBeanFactory(beanFactory);
        // 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析
        loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

refreshBeanFactory() 方法的另一个实现是在 GenericApplicationContext 中,Spring Boot 的纯注解就是调用这个方法,因为在 AnnotationConfigServletWebServerApplicationContext 的时候就将 IOC容器已经创建完毕了。

protected final void refreshBeanFactory() throws IllegalStateException {
    if (!this.refreshed.compareAndSet(false, true)) {
        throw new IllegalStateException(
            "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
    }
    this.beanFactory.setSerializationId(getId());
}

createBeanFactory()

在 createBeanFactory() 的方法中 new DefaultListableBeanFactory(),往其父类构造方法中能够找到这样一段代码,是 AbstractAutowireCapableBeanFactory 的构造方法。

public AbstractAutowireCapableBeanFactory() {
    super();
    // 忽略要依赖的接口,此处忽略的接口会在后面创建 Bean  的时候,判断是否进行回调。
    ignoreDependencyInterface(BeanNameAware.class);
    ignoreDependencyInterface(BeanFactoryAware.class);
    ignoreDependencyInterface(BeanClassLoaderAware.class);
}

customizeBeanFactory()

在 IoC 容器中设置的两个属性,在后面会使用到这两个参数。

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    // 如果属性allowBeanDefinitionOverriding不为空,设置给beanFactory对象相应属性,是否允许覆盖同名称的不同定义的对象
    if (this.allowBeanDefinitionOverriding != null) {
        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    // 如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性,是否允许bean之间存在循环依赖
    if (this.allowCircularReferences != null) {
        beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    }
}

loadBeanDefinitions(beanFactory)

这个方法有很多的重载方法,很容易迷,在这里简单说一下,loadBeanDefinition 方法主要有加载 String 路径形式的,Resource 资源形式的,还有数组类型的,但是数组类型最终会调回单个的形式,String 路径形式的,会封装成 Resource 资源的形式来进行加载。在此方法中会通过创建一个 BeanDefinitionReader 形式的读取器,来对资源文件进行,将解析后的资源形成 BeanDefinition,供后续创建 Bean 对象使用。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    // 创建一个xml的beanDefinitionReader,并通过回调设置到beanFactory中
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    // 给reader对象设置环境对象
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    //  初始化beanDefinitionReader对象,此处设置配置文件是否要进行验证
    initBeanDefinitionReader(beanDefinitionReader);
    // 开始完成beanDefinition的加载
    loadBeanDefinitions(beanDefinitionReader);
}

getConfigLocations()里面的数据来源于前面 setConfigLocations();

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    // 以Resource的方式获得配置文件的资源位置
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    // 以String的形式获得配置文件的位置
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }
}

reader.loadBeanDefinitions()

经过一系列的重载方法的处理,最终会调用 doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 对其资源文件进行处理,当然前面有一步涉及到将 String 类型的文件名转换为 Resource,然后进行处理

/** 转换的核心方法,这个地方的资源解析器来源于前面的构造方法 */
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);

异常信息给去掉了

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

    try {
        // 此处获取xml文件的document对象,这个解析过程是由documentLoader完成的,从String[] -string-Resource[]- resource,最终开始将resource读取成一个document文档,根据文档的节点信息封装成一个个的 BeanDefinition 对象
        Document doc = doLoadDocument(inputSource, resource);
        int count = registerBeanDefinitions(doc, resource);
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + count + " bean definitions from " + resource);
        }
        return count;
    }
}

registerBeanDefinitions(doc, resource)

具体的解析,注册逻辑,doLoadDocument 主要将 xml 对象解析封装为 Document 对象,这里主要说明 BeanDefinition 具体的解析逻辑。此处还涉及到后续自定义标签解析的一部分工作,在 createReaderContext(resource)方法中会创建 DefaultNamespaceHandlerResolver,此方法会在后续的时候加载 META-INF/spring.handlers 中的 uri 和解析器的一个对应关系。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   // 对xml的beanDefinition进行解析
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   int countBefore = getRegistry().getBeanDefinitionCount();
   // 完成具体的解析过程
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

调用的是默认的 DefaultBeanDefinitionDocumentReader#registerBeanDefinition

doRegisterBeanDefinitions()

具体的注册解析逻辑

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);
            // 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 之前,可以对其进行扩展 */
    preProcessXml(root);
    /** 解析 xml 形成 BeanDefinition */
    parseBeanDefinitions(root, this.delegate);
    /** 处理 xml 之后,可以对其进行扩展 */
    postProcessXml(root);

    this.delegate = parent;
}

parseBeanDefinitions

里面包含默认的 bean 标签的解析和其余自定义的标签的处理,这里暂时不对自定义标签的解析其进行具体的解析,在随后的一篇文章中说明。

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;
                if (delegate.isDefaultNamespace(ele)) {
                    parseDefaultElement(ele, delegate);
                }
                else {
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}

parseDefaultElement()

解析默认的标签,包含 import,alias、beans、bean等标签的解析,注意: beans标签的解析会是一个递归的过程,又会返回去调用 doRegisterBeanDefinitions(ele) 方法。

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
    }
}

processBeanDefinition(ele, delegate)

处理 BeanDefinition,主要是用 BeanDefinitionParserDelegate 策略对其进行解析,解析之后形成 BeanDefinitionHolder。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // beanDefinitionHolder是beanDefinition对象的封装类,封装了BeanDefinition,bean的名字和别名,用它来完成向IOC容器的注册
    // 得到这个beanDefinitionHolder就意味着beandefinition是通过BeanDefinitionParserDelegate对xml元素的信息按照spring的bean规则进行解析得到的
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            // 向ioc容器注册解析得到的beandefinition的地方
            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向ioc容器注册完成之后,发送消息
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

registerBeanDefinition()

将得到的 BeanDefinition 注册到 IOC 中。

public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    // 使用beanName做唯一标识注册
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // Register aliases for bean name, if any.
    // 注册所有的别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

registerBeanDefinition

方法存在于 DefaultListableBeanFactory 类中,主要存放在两个地方,一个为 beanDefinitionMap,beanName 为 key,BeanDefinition 为 value,beanDefinitionNames 中存放所有的 Bean 名称,在后续实例化所有剩下的 bean 中会使用,注意:beanDefinitionNames 中存放的名称是有顺序的。

至此 解析形成的 xml 已经注册到 IOC 中。

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

posted @ 2021-03-09 14:09  ice_image  阅读(94)  评论(0编辑  收藏  举报