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

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

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

    jinfeng_wang

    G-G-S,D-D-U!

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      400 Posts :: 0 Stories :: 296 Comments :: 0 Trackbacks
    代碼:sharding-jdbc-config-spring 目錄


    https://my.oschina.net/nalenwind/blog/599044


    spring擴(kuò)展之自定義標(biāo)簽 

        不知大家在看到那些大牛們?cè)趕pring里寫各種擴(kuò)展工具,各種方便有沒有很羨慕呢?接下來我給大家介紹一下如何通過自定義標(biāo)簽的形式來擴(kuò)展spring. 
        要通過自定義標(biāo)簽來擴(kuò)展spring,首先我們應(yīng)該知道spring是如何解析標(biāo)簽,并將其相關(guān)信息存儲(chǔ)在內(nèi)部數(shù)據(jù)結(jié)構(gòu)中的,這樣我們才能知道要實(shí)現(xiàn)或繼承覆寫那些接口或抽象類的函數(shù)。 

        spring在解析xml的過程中會(huì)執(zhí)行到DefaultBeanDifinitionDocumentReader類的parseBeanDefinitions函數(shù)代碼如下: 
    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函數(shù)是用來解析spring文檔中的默認(rèn)標(biāo)簽,像beans,import等等,而parseCustomElement函數(shù)就是用來解析我們自定義標(biāo)簽的入口了。代碼如下: 
    public BeanDefinition parseCustomElement(Element ele) {     return parseCustomElement(ele, null); }
    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {     String namespaceUri = getNamespaceURI(ele);     NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);     if (handler == null) {         error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);         return null;     }     return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
    這里首先獲取xml元素的命名空間,然后根據(jù)命名空間調(diào)哦嗯resolve函數(shù)來獲取一個(gè)NamespaceHandler,重點(diǎn)在這個(gè)resolve函數(shù)上。點(diǎn)進(jìn)去:(該函數(shù)所屬DefaultNamespaceHandlerResolver類) 
       
    public NamespaceHandler resolve(String namespaceUri) {     Map<String, Object> handlerMappings = getHandlerMappings();     Object handlerOrClassName = handlerMappings.get(namespaceUri);     if (handlerOrClassName == null) {         return null;     }     else if (handlerOrClassName instanceof NamespaceHandler) {         return (NamespaceHandler) handlerOrClassName;     }     else {         String className = (String) handlerOrClassName;         try {             Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);             if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {                 throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +                         "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");             }             NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);             namespaceHandler.init();             handlerMappings.put(namespaceUri, namespaceHandler);             return namespaceHandler;         }         catch (ClassNotFoundException ex) {             throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +                     namespaceUri + "] not found", ex);         }         catch (LinkageError err) {             throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +                     namespaceUri + "]: problem with handler class file or dependent class", err);         }     } }

    可以看到它首先獲取一個(gè)handlerMappings,然后剩下的工作就是去根據(jù)這個(gè)命名空間去獲取或使用反射去實(shí)例化一個(gè)NamespaceHandler, 
    實(shí)例話的時(shí)候會(huì)調(diào)用其init函數(shù)來初始化NamespaceHandler,這個(gè)函數(shù)中可以做一些注冊(cè)標(biāo)簽解析器的動(dòng)作,這個(gè)后續(xù)會(huì)詳細(xì)說明。下面不用我說,你肯定早就點(diǎn)進(jìn) getHandlerMappings函數(shù)看其實(shí)現(xiàn)了吧,這里面它根據(jù)handlerMappingsLocation指定的位置,默認(rèn)就是打好的jar包里的META-INF/spring.handlers文件,PropertiesLoaderUtils.loadAllProperties函數(shù)會(huì)把所有jar包下的META-INF/spring.handlers文件全部讀取一遍,將文件中的類似于 
    http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler 
    這個(gè)結(jié)構(gòu)的鍵值對(duì)存于properties中(這一鍵值對(duì)中指定了命名空間和命名空間處理器的對(duì)應(yīng)關(guān)系),轉(zhuǎn)成map從getHandlerMappings返回。所以我們需要編寫我們自己的NamespaceHandler類和指定映射關(guān)系的spring.handlers文件。 

    當(dāng)然要自定義標(biāo)簽,還要寫一個(gè)定義標(biāo)簽的xsd定義文件和將命名空間指定到你定義的xsd文件映射關(guān)系的文件spring.schemas文件, 
    spring.schemas文件和spring.handlers放到同一目錄下。schemas文件內(nèi)容示例如下: 
    http\://www.xxxx.com/schema/qmq/qmq-2.0.0.xsd=META-INF/qmq-2.0.0.xsd http\://www.xxxx.com/schema/qmq/qmq.xsd=META-INF/qmq-2.0.0.xsd
    spring中已經(jīng)給我們提供了一個(gè)NamespaceHandlerSupport抽象類,他里面提供了一個(gè)存儲(chǔ)標(biāo)簽名稱到BeanDefinitionParser標(biāo)簽解析器的映射關(guān)系的map,調(diào)用registerBeanDefinitionParser函數(shù)可以注冊(cè)BeanDefinitionParser到map中去解析相應(yīng)的標(biāo)簽。BeanDefinitionParser定義如下: 
    public interface BeanDefinitionParser {     BeanDefinition parse(Element element, ParserContext content); }
    這樣在上文的parseCustomElement中調(diào)用NamespaceHandler的parse函數(shù)的時(shí)候就會(huì)根據(jù)標(biāo)簽名稱調(diào)用我們注冊(cè)的解析器的parse函數(shù)代碼如下:(NamespaceHandlerSupport) 
    protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {         this.parsers.put(elementName, parser);     }       public BeanDefinition parse(Element element, ParserContext parserContext) {         return findParserForElement(element, parserContext).parse(element, parserContext);     }       private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {         String localName = parserContext.getDelegate().getLocalName(element);         BeanDefinitionParser parser = this.parsers.get(localName);         if (parser == null) {             parserContext.getReaderContext().fatal(                     "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);         }         return parser;     }
    剩下的工作就是編寫B(tài)eanDefinitionParser,spring中為我們提供了一個(gè)抽象類AbstractSingleBeanDefinitionParser來方便我們擴(kuò)展,上面說道BeanDefinitionParser的入口函數(shù)是parse,這個(gè)函數(shù)的實(shí)現(xiàn)在AbstractBeanDefinitionParser類中,代碼如下: 

       
    public final BeanDefinition parse(Element element, ParserContext parserContext) {         AbstractBeanDefinition definition = parseInternal(element, parserContext);         if (definition != null && !parserContext.isNested()) {             try {                 String id = resolveId(element, definition, parserContext);                 if (!StringUtils.hasText(id)) {                     parserContext.getReaderContext().error(                             "Id is required for element '" + parserContext.getDelegate().getLocalName(element)                                     + "' when used as a top-level tag", element);                 }                 String[] aliases = new String[0];                 String name = element.getAttribute(NAME_ATTRIBUTE);                 if (StringUtils.hasLength(name)) {                     aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));                 }                 BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);                 registerBeanDefinition(holder, parserContext.getRegistry());                 if (shouldFireEvents()) {                     BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);                     postProcessComponentDefinition(componentDefinition);                     parserContext.registerComponent(componentDefinition);                 }             }             catch (BeanDefinitionStoreException ex) {                 parserContext.getReaderContext().error(ex.getMessage(), element);                 return null;             }         }         return definition;     }
    這里首先調(diào)用parseInternal函數(shù)解析出一個(gè)BeanDefinition,然后解析兩個(gè)通用的屬性id和name,我們看parseInternal函數(shù),它的實(shí)現(xiàn)在子類AbstractSingleBeanDefinitionParser中: 
       
    protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {         BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();         String parentName = getParentName(element);         if (parentName != null) {             builder.getRawBeanDefinition().setParentName(parentName);         }         Class<?> beanClass = getBeanClass(element);         if (beanClass != null) {             builder.getRawBeanDefinition().setBeanClass(beanClass);         }         else {             String beanClassName = getBeanClassName(element);             if (beanClassName != null) {                 builder.getRawBeanDefinition().setBeanClassName(beanClassName);             }         }         builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));         if (parserContext.isNested()) {             // Inner bean definition must receive same scope as containing bean.             builder.setScope(parserContext.getContainingBeanDefinition().getScope());         }         if (parserContext.isDefaultLazyInit()) {             // Default-lazy-init applies to custom bean definitions as well.             builder.setLazyInit(true);         }         doParse(element, parserContext, builder);         return builder.getBeanDefinition();     }
    這里先獲取bean的parentname,然后獲取bean的class,我們看到他先調(diào)用的是getBeanClass函數(shù),如果反回空才會(huì)調(diào)用getBeanClassName,所以我們覆寫AbstractSingleBeanDefinitionParser類的時(shí)候只要實(shí)現(xiàn)這兩個(gè)中的一個(gè)函數(shù)就可以了,通常是getBeanClass。從上面的函數(shù)中我們還可以看到最后的解析全部委托給了doParse函數(shù),我們解析自己的自定義標(biāo)簽就在這個(gè)函數(shù)中實(shí)現(xiàn)。如果需要更改bean的表示id,還可以覆寫resolveId函數(shù)。 

    好了,道理講完了,上代碼,代碼示例取自《spring源碼深度剖析》69頁起: 

    定義bean用來接收配置: public class User {     private String userName;     private String email;     //省略set,get方法 }  定義xsd文件user.xsd: <?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.excample.com/schema/user" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.excample.com/schema/user" elementFormDefault="qualified">     <xsd:element name="user">         <xsd:complexType>             <xsd:attribute name="id" type="xsd:string"/>             <xsd:attribute name="userName" type="xsd:string"/>             <xsd:attribute name="email" type="xsd:string"/>         </xsd:complexType>     </xsd:element> </xsd:schema>   定義BeanDefinitionParser: public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {     @Override     protected Class getBeanClass(Element element) {         return User.class;     }       @Override     protected void doParse(Element element, BeanDefinitionBuilder builder) {         String userName = element.getAttribute("userName");         String email = element.getAttribute("email");         builder.addPropertyValue("userName", userName);         builder.addPropertyValue("email", email);     } }   定義NamespaceHandler: public class MyNamespaceHandler extends NamespaceHandlerSupport {     public void init() {         registerBeanDefinitionParser("user", new UserBeanDefinitionParser());     } }   spring.handlers: http\://http://www.example.com/schema/user=MyNamespaceHandler   spring.schemas: http\://http://www.example.com/schema/user.xsd=META-INF/user.xsd   測(cè)試: spring.xml配置文件: <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:user="http://www.example.com/schema/user" xsi:schemaLocation="http://www.springframework.org/schema/beans         http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.example.com/schema/user http://www.example.com/schema/user.xsd">       <user:user id="user" userName="test" email="test"/> </beans>   public static void main(String[] s) {     ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");     User user = (User)context.getBean("user");     System.out.print(user.getUesrName() + user.getEmail()); }



    posted on 2016-12-28 19:01 jinfeng_wang 閱讀(406) 評(píng)論(0)  編輯  收藏 所屬分類: 2016-Sharding-JDBC

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲国产a级视频| 免费在线不卡视频| 日韩伦理片电影在线免费观看| 免费高清小黄站在线观看| 亚洲AV成人潮喷综合网| 亚洲精品无码不卡在线播放HE| 久久亚洲AV无码精品色午夜麻豆| 亚洲午夜一区二区三区| 亚洲av日韩av永久在线观看| 成人免费777777被爆出| 亚洲免费中文字幕| 国产人成免费视频| 久久亚洲精品成人| 亚洲人成网站在线播放2019| 日本一区二区在线免费观看| 亚欧免费一级毛片| 日韩在线免费看网站| 久久精品国产亚洲麻豆| ASS亚洲熟妇毛茸茸PICS| 免费人成再在线观看网站| 午夜视频免费在线观看| 日韩黄色免费观看| 亚洲αv在线精品糸列| 久久亚洲国产最新网站| 中国精品一级毛片免费播放| 国产无人区码卡二卡三卡免费| 亚洲Av无码国产情品久久| 亚洲精品人成电影网| fc2成年免费共享视频网站| 国产免费的野战视频| 亚洲伊人久久综合影院| 亚洲jjzzjjzz在线播放| 在线观看黄片免费入口不卡| 最近的免费中文字幕视频| 亚洲国产成人一区二区三区| 亚洲风情亚Aⅴ在线发布| 99久久人妻精品免费二区| 亚洲黄片毛片在线观看| 久久精品国产99国产精品亚洲| 国产乱子伦精品免费视频| 女人与禽交视频免费看|