<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 12, 文章 - 0, 評論 - 22, 引用 - 0
    數據加載中……

    Spring加載資源分析

    說明:
        這篇文檔是對Spring加載和解析xml文件過程的分析,下面看一個spring解析xml文件的測試例子。
        @Test
        public void test3BeanDefinitionReader(){
            DefaultResourceLoader loader = new DefaultResourceLoader();
            Resource resource = loader.getResource("/ioc/application.xml");
            BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
            BeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
            
            int count = reader.loadBeanDefinitions(resource);
            String[] beanDefinitionNames = reader.getRegistry().getBeanDefinitionNames();
            System.out.println("----------------------");
            for (String name : beanDefinitionNames) {
                System.out.println(name);
            }
        }

    針對以上例子,得出Spring解析xml文件的流程圖和結構圖:






    Spring解析配置文件中用到的一些關鍵類的介紹:
    • Resource:各種資源的抽象接口,包括xml文件,網絡上的資源等。
    • BeanDefinitionRegistry:用于注冊BeanDefinitionRegistry。
    • BeanDefinitionReader:用于讀取解析Resource的抽象接口。
    • DefaultBeanDefinitionDocumentReader:實現(xiàn)了BeanDefinitionDocumentReader接口,DefaultBeanDefinitionDocumentReader并不負責任何具體的bean解析,它面向的是xml Document對象,根據其元素的命名空間和名稱,起一個類似路由的作用((不過,命名空間的判斷,也是委托給delegate來做的),它跟BeanDefinitionParserDelegate協(xié)同合作,把解析任務交接BeanDefinitionParserDelegate來做。
    • BeanDefinitionParserDelegate:完成具體Bean的解析(比如<bean>、<import>、<alias>標簽),對于擴展的標簽會交給不同的NamespaceHandler跟BeanDefinitionParser來解析。
    • BeanDefinitionParser:解析配置文件成相應的BeanDefinition(<context:component-scan>,<aop:config>等標簽都是又不同的BeanDefinitionParser來解析),一般在NamespaceHandler中使用。Spring也為自定義BeanDefinitionParser提供了很多支持,在一些抽象類的基礎上添加少量功能即可滿足大部分需求。
    • NamespaceHandler:要解析自定義的bean就要通過自己所實現(xiàn)的NamespaceHandler來進行解析。比如定義了http\://www.springframework.org/schema/osgi=org.springframework.osgi.config.OsgiNamespaceHandler,那么在碰到osgi的scheme的時候就會去調用OsgiNamespaceHandler來進行解析; 在對于普通的擴展需求來說,只要讓自己的Handler繼承NamespaceHandlerSupport并實現(xiàn) init()方法 就好了,對于特殊的擴展需求 則可以自己 來實現(xiàn)NamespaceHandler。

    下面來分析一下源代碼:
    源碼1:加載xml文件
    XmlBeanDefinitionReader:
        public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
            //加載xml資源
            return loadBeanDefinitions(new EncodedResource(resource));
        }
     
        public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
                
                InputStream inputStream = encodedResource.getResource().getInputStream();
                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        //設置字符集
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                }

        }

        protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
            try {
                int validationMode = getValidationModeForResource(resource);
                //根據xml文件,得到標準的Document對象
                Document doc = this.documentLoader.loadDocument(
                        inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
                return registerBeanDefinitions(doc, resource);

        }
     
        public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            //BeanDefinitionDocumentReader實際解析doc文檔
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            int countBefore = getRegistry().getBeanDefinitionCount();
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }
     
    DefaultBeanDefinitionDocumentReader:
        public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {

            Element root = doc.getDocumentElement();
            //元素解析的代理類,主要的bean解析,以及一些自定義元素的解析
            BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
            //默認為空操作
            preProcessXml(root);
            //解析元素
            parseBeanDefinitions(root, delegate);
            postProcessXml(root);
        }
     
        protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            //默認命名空間為http://www.springframework.org/schema/beans,也就是xml文件中<bean>的標簽
            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 {
                            //處理自定義標簽 (i.e.  AOP,CONTENT,JDBC)
                            delegate.parseCustomElement(ele);
                        }
                    }
                }
            }
            else {//處理自定義標簽
                delegate.parseCustomElement(root);
            }
        }

    源碼2:基本元素解析(i.e.  <bean>、<import>......)
    DefaultBeanDefinitionDocumentReader:
        private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
            if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
                //解析<import>標簽
                importBeanDefinitionResource(ele);
            }
            else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
                //解析<alias>標簽
                processAliasRegistration(ele);
            }
            else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
                //解析<bean>標簽
                processBeanDefinition(ele, delegate);
            }
        }
     
        protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
            //解析element,得到BeanDefinition,BeanDefinitionHolder中包含了BeanDefinition
            BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

                    //注冊BeanDefinition
                    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

        }
     
    BeanDefinitionParserDelegate:
        public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
            return parseBeanDefinitionElement(ele, null);
        }
     
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
            String id = ele.getAttribute(ID_ATTRIBUTE);
            String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
            List<String> aliases = new ArrayList<String>();
            if (StringUtils.hasLength(nameAttr)) {
                String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);
                aliases.addAll(Arrays.asList(nameArr));
            }
            String beanName = id;

            if (containingBean == null) {
                //檢查bean name的唯一性
                checkNameUniqueness(beanName, aliases, ele);
            }
            //解析Element
            AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
            if (beanDefinition != null) {

                String[] aliasesArray = StringUtils.toStringArray(aliases);
                return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
            }
            return null;
        }
     
    //真正解析<bean>的地方
    public AbstractBeanDefinition parseBeanDefinitionElement(
                Element ele, String beanName, BeanDefinition containingBean) {
            this.parseState.push(new BeanEntry(beanName));
            String className = null;
            if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
                className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
            }

                String parent = null;
                if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                    parent = ele.getAttribute(PARENT_ATTRIBUTE);
                }
                AbstractBeanDefinition bd = createBeanDefinition(className, parent);
                parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
                bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
                parseMetaElements(ele, bd);
                parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
                parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
                parseConstructorArgElements(ele, bd);
                parsePropertyElements(ele, bd);
                parseQualifierElements(ele, bd);
                bd.setResource(this.readerContext.getResource());
                bd.setSource(extractSource(ele));
                return bd;

            return null;
        }

    源碼3:處理擴展或自定義標簽:
    BeanDefinitionParserDelegate:
        public BeanDefinition parseCustomElement(Element ele) {
            return parseCustomElement(ele, null);
        }

        public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
            String namespaceUri = getNamespaceURI(ele);
            //根據元素的命名空間得到NamespaceHandler
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

            //使用合適的NamespaceHandler解析元素
            return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
        }

    NamespaceHandlerSupport:
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            //得到真正具體處理自定義的BeanDefinitionParser,解析element得到BeanDefinition
            return findParserForElement(element, parserContext).parse(element, parserContext);
        }


        private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
            String localName = parserContext.getDelegate().getLocalName(element);
            //parsers中包含了具體處理自定義標簽的類
            BeanDefinitionParser parser = this.parsers.get(localName);

            return parser;
        }


    代碼3.2:在源碼3.1中代碼:{NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)}這步中,展示了對于擴展或自定義的標簽的處理類是從哪里加載的
       public NamespaceHandler resolve(String namespaceUri) {
            //得到Map<Element名稱,NamespaceHandler處理類>
            Map<String, Object> handlerMappings = getHandlerMappings();
            //根據namespaceUri得到匹配的NamespaceHandler
            Object handlerOrClassName = handlerMappings.get(namespaceUri);
            if (handlerOrClassName == null) {
                return null;
            }
            else if (handlerOrClassName instanceof NamespaceHandler) {
                return (NamespaceHandler) handlerOrClassName;
            }else{

                    }
        }

        private Map<String, Object> getHandlerMappings() {

    //handlerMappingsLocation默認值:META-INF/spring.handlers
    //
    spring就會從jar包中的Meta-INF/spring.handlers文件中得到處理各種不同命名空間元素的類
                            Properties mappings =
                                    PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);

                            Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>();
                            CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                            this.handlerMappings = handlerMappings;

            return this.handlerMappings;
        }

          當初一直在想Spring是如何解析自定義元素(i.e. <context:component-scan>,<aop:config> )。通過源碼分析看出spring在解析的過程中,會去收集spring.*.jar/META-INF下的spring.handers,spring.schemas文件,這2個文件就是指明了解析spring中自定義標簽的Namespace類。如果自己開發(fā)Spring組件,需要增加新的標簽,也可以按照這個機制。

    參考:
    http://kyfxbl.iteye.com/blog/1610255 (小讀spring ioc源碼)
    http://blog.csdn.net/cutesource/article/details/5864562 (基于Spring可擴展Schema提供自定義配置支持)

    posted on 2013-10-28 00:12 heavensay 閱讀(11410) 評論(2)  編輯  收藏 所屬分類: java spring

    評論

    # re: Spring加載資源分析  回復  更多評論   

    謝謝博主分享
    2013-10-28 12:44 | 魏五鎖業(yè)

    # re: Spring加載資源分析  回復  更多評論   

    是春天來了嗎
    2013-10-29 12:48 | 太陽城娛樂城

    只有注冊用戶登錄后才能發(fā)表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲免费精彩视频在线观看| 日韩精品极品视频在线观看免费| 亚洲精品国产精品乱码不卡| 国产精品亚洲综合五月天| 日韩精品视频免费观看| 中文字幕在线日亚洲9| 免费人成网站7777视频| 久久成人免费大片| 亚洲Av永久无码精品黑人| 亚洲人成在线播放网站| 三级毛片在线免费观看| 亚洲久悠悠色悠在线播放| 久久久久亚洲AV成人网| 台湾一级毛片永久免费| yy一级毛片免费视频| 国产专区一va亚洲v天堂| 啦啦啦完整版免费视频在线观看 | 国产精品日本亚洲777| 国产亚洲精品美女久久久| 免费下载成人电影| 久久99精品免费一区二区| 国产精品亚洲综合五月天| 亚洲av无码精品网站| 18禁美女裸体免费网站| 曰韩无码AV片免费播放不卡| 亚洲精品人成电影网| 亚洲人成网亚洲欧洲无码久久 | 无码欧精品亚洲日韩一区| 国产高清视频在线免费观看| 69视频免费观看l| 久久久久久久国产免费看| 亚洲爆乳大丰满无码专区| 91亚洲国产成人久久精品网站| 亚洲A∨午夜成人片精品网站| 久久久久久国产精品免费免费| 日韩精品免费视频| 久久免费香蕉视频| 香港特级三A毛片免费观看| 亚洲一区二区三区在线观看网站| 久久精品国产亚洲av水果派| 亚洲人成影院在线无码按摩店|