成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Spring解密 - 自定義標(biāo)簽與解析

Taste / 3508人閱讀

摘要:自定義標(biāo)簽在講解自定義標(biāo)簽解析之前,先看下如何自定義標(biāo)簽定義文件定義一個(gè)文件描述組件內(nèi)容聲明命名空間值得注意的是與可以是不存在,只要映射到指定就行了。

Spring是一個(gè)開(kāi)源的設(shè)計(jì)層面框架,解決了業(yè)務(wù)邏輯層和其他各層的松耦合問(wèn)題,將面向接口的編程思想貫穿整個(gè)系統(tǒng)應(yīng)用,同時(shí)它也是Java工作中必備技能之一...

前言

在 上一節(jié) Spring解密 - 默認(rèn)標(biāo)簽的解析 中,重點(diǎn)分析了 Spring 對(duì)默認(rèn)標(biāo)簽是如何解析的,那么本章繼續(xù)講解標(biāo)簽解析,著重講述如何對(duì)自定義標(biāo)簽進(jìn)行解析。

自定義標(biāo)簽

在講解 自定義標(biāo)簽解析 之前,先看下如何自定義標(biāo)簽

定義 XSD 文件

定義一個(gè) XSD 文件描述組件內(nèi)容




    

    
        
            
                
                    
                
            
        
    

聲明命名空間: 值得注意的是 xmlnstargetNamespace 可以是不存在,只要映射到指定 XSD 就行了。

定義復(fù)合元素: 這里的 application 就是元素的名稱(chēng),使用時(shí)

定義元素屬性: 元素屬性就是 attribute 標(biāo)簽,我們聲明了一個(gè)必填的 name 的屬性,使用時(shí)

定義解析規(guī)則

1.創(chuàng)建一個(gè)類(lèi)實(shí)現(xiàn) BeanDefinitionParser 接口(也可繼承 Spring 提供的類(lèi)),用來(lái)解析 XSD 文件中的定義和組件定義

public class ApplicationBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    @Override
    protected Class getBeanClass(Element element) {
        // 接收對(duì)象的類(lèi)型 如:String name = (String) context.getBean("battcn");
        return String.class;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        // 在 xsd 中定義的 name 屬性
        String name = element.getAttribute("name");
        bean.addConstructorArgValue(name);
    }
}

這里創(chuàng)建了一個(gè) ApplicationBeanDefinitionParser 繼承 AbstractSingleBeanDefinitionParser(是:BeanDefinitionParser 的子類(lèi)), 重點(diǎn)就是重寫(xiě)的 doParse,在這個(gè)里面解析 XML 標(biāo)簽的,然后將解析出的 value(Levin) 通過(guò)構(gòu)造器方式注入進(jìn)去

2.創(chuàng)建一個(gè)類(lèi)繼承 NamespaceHandlerSupport 抽象類(lèi)

public class BattcnNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("application", new ApplicationBeanDefinitionParser());
    }

}

BattcnNamespaceHandler 的作用特別簡(jiǎn)單,就是告訴 Spring 容器,標(biāo)簽 應(yīng)該由那個(gè)解析器解析(這里是我們自定義的:ApplicationBeanDefinitionParser),負(fù)責(zé)將組件注冊(cè)到 Spring 容器

3.編寫(xiě) spring.handlersspring.schemas 文件

文件存放的目錄位于 resources/META-INF/文件名

spring.handlers
http://www.battcn.com/schema/battcn=com.battcn.handler.BattcnNamespaceHandler
spring.schemas
http://www.battcn.com/schema/battcn.xsd=battcn.xsd

4.使用自定義標(biāo)簽

申明 bean.xml 文件,定義如下




    

創(chuàng)建一個(gè)測(cè)試類(lèi),如果看到控制臺(tái)輸出了 Levin 字眼,說(shuō)明自定義標(biāo)簽一切正常

public class Application {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        String name = (String) context.getBean("battcn");
        System.out.println(name);

    }
}

5.如圖所示

源碼分析
自定義標(biāo)簽解析入口
public class BeanDefinitionParserDelegate {

    @Nullable
    public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
        // 獲取命名空間地址 http://www.battcn.com/schema/battcn
        String namespaceUri = getNamespaceURI(ele);
        if (namespaceUri == null) {
            return null;
        }
        // NamespaceHandler 就是 自定義的 BattcnNamespaceHandler 中注冊(cè)的 application
        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));
    }

}

與默認(rèn)標(biāo)簽解析規(guī)則一樣的是,都是通過(guò) getNamespaceURI(Node node) 來(lái)獲取命名空間,那么 this.readerContext.getNamespaceHandlerResolver() 是從哪里獲取的呢?我們跟蹤下代碼,可以發(fā)現(xiàn)在項(xiàng)目啟動(dòng)的時(shí)候,會(huì)在 XmlBeanDefinitionReader 將所有的 META-INF/spring.handles 文件內(nèi)容解析,存儲(chǔ)在 handlerMappers(一個(gè)ConcurrentHashMap) 中,在調(diào)用 resolve(namespaceUri) 校驗(yàn)的時(shí)候在將緩存的內(nèi)容提取出來(lái)做對(duì)比

public class XmlBeanDefinitionReader {

    public NamespaceHandlerResolver getNamespaceHandlerResolver() {
        if (this.namespaceHandlerResolver == null) {
            this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
        }
        return this.namespaceHandlerResolver;
    }

}
resolve

1.加載指定的 NamespaceHandler 映射,并且提取的 NamespaceHandler 緩存起來(lái),然后返回

public class DefaultNamespaceHandlerResolver {

    @Override
    @Nullable
    public NamespaceHandler resolve(String namespaceUri) {
        Map handlerMappings = getHandlerMappings();
        // 從 handlerMappings 提取 handlerOrClassName
        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");
                }
                // 根據(jù)命名空間尋找對(duì)應(yīng)的信息
                NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
                // Handler 初始化
                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);
            }
        }
    }

}
標(biāo)簽解析

加載完 NamespaceHandler 之后,BattcnNamespaceHandler 就已經(jīng)被初始化為 了,而 BattcnNamespaceHandler 也調(diào)用了 init() 方法完成了初始化的工作。因此就接著執(zhí)行這句代碼: handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); 具體標(biāo)簽解。

public class NamespaceHandlerSupport {

    @Override
    @Nullable
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        BeanDefinitionParser parser = findParserForElement(element, parserContext);
        return (parser != null ? parser.parse(element, parserContext) : null);
    }

    @Nullable
    private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        // 解析出  中的  application
        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;
    }


}

簡(jiǎn)單來(lái)說(shuō)就是從 parsers 中尋找到 ApplicationBeanDefinitionParser 實(shí)例,并調(diào)用其自身的 doParse 方法進(jìn)行進(jìn)一步解析。最后就跟解析默認(rèn)標(biāo)簽的套路一樣了...

總結(jié)

熬過(guò)幾個(gè)無(wú)人知曉的秋冬春夏,撐過(guò)去一切都會(huì)順著你想要的方向走...

說(shuō)點(diǎn)什么

全文代碼:https://gitee.com/battcn/battcn-spring-source/tree/master/Chapter2

個(gè)人QQ:1837307557

battcn開(kāi)源群(適合新手):391619659

微信公眾號(hào):battcn(歡迎調(diào)戲)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68242.html

相關(guān)文章

  • Spring解密 - 默認(rèn)標(biāo)簽解析

    Spring是一個(gè)開(kāi)源的設(shè)計(jì)層面框架,解決了業(yè)務(wù)邏輯層和其他各層的松耦合問(wèn)題,將面向接口的編程思想貫穿整個(gè)系統(tǒng)應(yīng)用,同時(shí)它也是Java工作中必備技能之一... 前言 緊跟上篇 Spring解密 - XML解析 與 Bean注冊(cè) ,我們接著往下分析源碼 解密 在 Spring 的 XML 配置里面有兩大類(lèi)聲明,一個(gè)是默認(rèn)的如 ,另一類(lèi)就是自定義的如,兩種標(biāo)簽的解析方式差異是非常大的。parseBe...

    snowLu 評(píng)論0 收藏0
  • Spring解密 - XML解析 Bean注冊(cè)

    摘要:解密是注冊(cè)及加載的默認(rèn)實(shí)現(xiàn),整個(gè)模板中它可以稱(chēng)得上始祖。中是這樣介紹的自動(dòng)裝配時(shí)忽略給定的依賴(lài)接口,比如通過(guò)其他方式解析上下文注冊(cè)依賴(lài),類(lèi)似于通過(guò)進(jìn)行的注入或者通過(guò)進(jìn)行的注入。解析是資源文件讀取解析注冊(cè)的實(shí)現(xiàn),要重點(diǎn)關(guān)注該類(lèi)。 Spring是一個(gè)開(kāi)源的設(shè)計(jì)層面框架,解決了業(yè)務(wù)邏輯層和其他各層的松耦合問(wèn)題,將面向接口的編程思想貫穿整個(gè)系統(tǒng)應(yīng)用,同時(shí)它也是Java工作中必備技能之一......

    cncoder 評(píng)論0 收藏0
  • Spring Cloud 參考文檔(Spring Cloud Config Server)

    摘要:,這是標(biāo)記配置文件集版本化的服務(wù)器端特性。要配置對(duì)稱(chēng)密鑰,需要將設(shè)置為秘密字符串或使用環(huán)境變量將其排除在純文本配置文件之外。 Spring Cloud Config Server Spring Cloud Config Server為外部配置提供基于HTTP資源的API(名稱(chēng)—值對(duì)或等效的YAML內(nèi)容),通過(guò)使用@EnableConfigServer注解,服務(wù)器可嵌入Spring Bo...

    harryhappy 評(píng)論0 收藏0
  • Spring Cloud 參考文檔(Spring Cloud Context:應(yīng)用程序上下文服務(wù))

    摘要:它們的優(yōu)先級(jí)低于或以及作為創(chuàng)建應(yīng)用程序過(guò)程的正常部分添加到子級(jí)的任何其他屬性源。為引導(dǎo)配置類(lèi)使用單獨(dú)的包名稱(chēng),并確?;蜃⒔獾呐渲妙?lèi)尚未涵蓋該名稱(chēng)。在這種情況下,它會(huì)在刷新時(shí)重建,并重新注入其依賴(lài)項(xiàng),此時(shí),它們將從刷新的重新初始化。 Spring Cloud Context:應(yīng)用程序上下文服務(wù) Spring Boot有一個(gè)關(guān)于如何使用Spring構(gòu)建應(yīng)用程序的主見(jiàn),例如,它具有通用配置文...

    魏明 評(píng)論0 收藏0
  • API數(shù)據(jù)加密框架monkey-api-encrypt

    摘要:相比之前的變化內(nèi)置加密算法,可以配置不同的加密不再綁定,通過(guò)配置即可使用加解密框架也可以支持支持用戶(hù)自定義加密算法地址示例代碼沒(méi)有發(fā)布到中央倉(cāng)庫(kù),只發(fā)布到這個(gè)倉(cāng)庫(kù),大家也可以自行下載源碼打包傳到自己公司的私服上。 之前有寫(xiě)過(guò)一篇加密的文章《前后端API交互如何保證數(shù)據(jù)安全性》。主要是在Spring Boot中如何對(duì)接口的數(shù)據(jù)進(jìn)行自動(dòng)加解密操作,通過(guò)注解的方式來(lái)指定是否需要加解密。 原理...

    BetaRabbit 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<