spring源码解读(1)-容器基本实现

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取10G资料包与项目实战视频资料

学习spring源码对理解spring的执行流程,如何更好的发挥spring的功能有很大的指导作用。下面针对spring加载bean容器学习spring的执行流程。

spring通过调用xml配置文件,解析并加载Bean,xmlBeanDefinitionReader则是整个资源加载的切入点:

2019112310084\_1.png

spring从xmlBeanReader读取BeanDifinition(Bean定义实体),首先使用encodedResouce进行封装,对resource进行编码设置;然后通过resource封装的输入流getinputStream,获得InputSource(sax-simple API XML的输入源);关键逻辑doLoadBeanDefinitions(inputsource,resource)实现实体bean的加载。

往下执行,要查询xml的验证模式,加载xml文件,转化为document对象,根据document对象注册Bean;

xml文件的验证模式验证xml文件的正确性,分为两种,DTD(document type definition)文档类型定义,比较xml和DTD检查文档是否符合规范,元素和标签是否正确,主要包括,元素定义规则,元素间关系规则,可使用属性、实体和符号规则。XSD(XML Schema Definition),检验的方式主要通过声明命名空间和文档存储位置。

2019112310084\_2.png

从上图可以看出,验证xml,首先获取EntityResourlver对象,解析xml,SAX首先读取XML文档上的声明,根据声明寻找DTD,默认从网络上寻找DTD声明,但是一旦网络出现问题,将无法顺利进行,EntityResolver的作用就是在本地保存DTD的声明。它的加载过程,首先获得抽象容器定义加载器获得资源加载器ResourceLoader,将resourceLoader作为参数加载EntityResourlver。

获取xml验证模式:getValidationModeForResource(reousrce),主要有两种验证模式,手动验证和自动验证:

        /**
         * Gets the validation mode for the specified {@link Resource}. If no explicit
         * validation mode has been configured then the validation mode is
         * {@link #detectValidationMode detected}.
         * <p>Override this method if you would like full control over the validation
         * mode, even when something other than {@link #VALIDATION_AUTO} was set.
         */
        protected int getValidationModeForResource(Resource resource) {
            int validationModeToUse = getValidationMode();
            //如果手动检测则使用指定验证方式
            if (validationModeToUse != VALIDATION_AUTO) {
                return validationModeToUse;
            }
            //如果未指定则使用自动检测
            int detectedMode = detectValidationMode(resource);
            if (detectedMode != VALIDATION_AUTO) {
                return detectedMode;
            }
            // Hmm, we didn't get a clear indication... Let's assume XSD,
            // since apparently no DTD declaration has been found up until
            // detection stopped (before finding the document's root tag).
            return VALIDATION_XSD;
        }

接下来就是加载document对象,首先创建document构建类的工厂,获得documentBuilder,然后对inputsource进行解析parse(inputSource),解析过程为SchemaValidation的复位,document的解析:

     /**
         * parse
         *
         * @param inputSource
         *
         * @exception XNIException
         * @exception java.io.IOException
         */
        public void parse(XMLInputSource inputSource)
            throws XNIException, IOException {
            // null indicates that the parser is called directly, initialize them
            if (securityManager == null) {
                securityManager = new XMLSecurityManager(true);
                fConfiguration.setProperty(Constants.SECURITY_MANAGER, securityManager);
            }
            if (securityPropertyManager == null) {
                securityPropertyManager = new XMLSecurityPropertyManager();
                fConfiguration.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager);
            }

            reset();
            fConfiguration.parse(inputSource);

        } // parse(XMLInputSource

最后通过document的验证器返回document对象: Document doc = domParser.getDocument();

最后一步,解析和注册bean:

2019112310084\_3.png

源码与解析:

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            //使用defaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            //记录当前beanDefiniton加载个数
            int countBefore = getRegistry().getBeanDefinitionCount();
            //加载并注册bean
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            //记录本次加载的beanDefinition个数
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }

其中最核心的是加载注册bean:documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

    /**
         * This implementation parses bean definitions according to the "spring-beans" XSD
         * (or DTD, historically).
         * <p>Opens a DOM Document; then initializes the default settings
         * specified at the {@code <beans/>} level; then parses the contained bean definitions.
         */
        @Override
        public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
            logger.debug("Loading bean definitions");
            //获取document的根节点
            Element root = doc.getDocumentElement();
            doRegisterBeanDefinitions(root);
        }
    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.
            //解析器--专门处理解析
            BeanDefinitionParserDelegate parent = this.delegate;
            this.delegate = createDelegate(getReaderContext(), root, parent);

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

            preProcessXml(root);
            parseBeanDefinitions(root, this.delegate);
            postProcessXml(root);

            this.delegate = parent;
        }
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            //对beans的处理
            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)) {
                            //对bean的处理,如果是默认命名空间采用该方法解析
                            parseDefaultElement(ele, delegate);
                        }
                        else {
                            //对bean处理,自定义方法命名空间
                            delegate.parseCustomElement(ele);
                        }
                    }
                }
            }
            else {
                delegate.parseCustomElement(root);
            }
        }

默认方法解析:

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

【总结】

源码只是粗略的了解了xml加载bean的过程,都说,源码是设计模式的集合体,希望通过接下来的研究能够将隐藏在其中的设计模式逐渐读懂!


来源:http://ddrv.cn/a/88268

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring源码解读(1)-容器基本实现

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏