zoukankan      html  css  js  c++  java
  • 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);
    

  • 相关阅读:
    自己的文件管理软件,想怎样分类管理就怎样分类
    给博客园发展支点招
    看看自己存在哪些的个人知识管理问题和烦恼呢?
    2008年个人知识管理软件测评[草稿]
    獲取某天是星期幾
    創建鏈接服務器
    在.NET中调用Oracle9i存储过程经验总结
    C#转换成VB.net或vb.net转换成C#
    話說我們家姚明
    解决winxp搜索不到文件的问题!
  • 原文地址:https://www.cnblogs.com/ice-image/p/14505200.html
Copyright © 2011-2022 走看看