国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

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

Taste / 3494人閱讀

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

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

前言

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

自定義標(biāo)簽

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

定義 XSD 文件

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




    

    
        
            
                
                    
                
            
        
    

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

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

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

定義解析規(guī)則

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

public class ApplicationBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    @Override
    protected Class getBeanClass(Element element) {
        // 接收對象的類型 如: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)建了一個 ApplicationBeanDefinitionParser 繼承 AbstractSingleBeanDefinitionParser(是:BeanDefinitionParser 的子類), 重點就是重寫的 doParse,在這個里面解析 XML 標(biāo)簽的,然后將解析出的 value(Levin) 通過構(gòu)造器方式注入進(jìn)去

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

public class BattcnNamespaceHandler extends NamespaceHandlerSupport {

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

}

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

3.編寫 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)建一個測試類,如果看到控制臺輸出了 Levin 字眼,說明自定義標(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 中注冊的 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ī)則一樣的是,都是通過 getNamespaceURI(Node node) 來獲取命名空間,那么 this.readerContext.getNamespaceHandlerResolver() 是從哪里獲取的呢?我們跟蹤下代碼,可以發(fā)現(xiàn)在項目啟動的時候,會在 XmlBeanDefinitionReader 將所有的 META-INF/spring.handles 文件內(nèi)容解析,存儲在 handlerMappers(一個ConcurrentHashMap) 中,在調(diào)用 resolve(namespaceUri) 校驗的時候在將緩存的內(nèi)容提取出來做對比

public class XmlBeanDefinitionReader {

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

}
resolve

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

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ù)命名空間尋找對應(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;
    }


}

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

總結(jié)

熬過幾個無人知曉的秋冬春夏,撐過去一切都會順著你想要的方向走...

說點什么

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

個人QQ:1837307557

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

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

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/68242.html

相關(guān)文章

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

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

    snowLu 評論0 收藏0
  • Spring解密 - XML解析 Bean注冊

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

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

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

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

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

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

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

    BetaRabbit 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<