最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mybatis解析xml配置中${xxx}占位符的代碼邏輯

 更新時間:2023年05月11日 11:00:51   作者:娘子醉了  
本文主要介紹了mybatis解析xml配置中${xxx}占位符的代碼邏輯,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧<BR>

涉及到的類以及關(guān)鍵邏輯

XNode

mybatis 在解析節(jié)點時使用的是 w3c 提供的 XML 解析工具,其類型為 org.w3c.dom.Node;但 mybatis 會使用 XNode 將其包裝,并且在 XNode 的構(gòu)造函數(shù)中就直接完成了占位符參數(shù)的解析:

 public XNode(XPathParser xpathParser, Node node, Properties variables) {
   this.xpathParser = xpathParser;
   this.node = node;
   this.name = node.getNodeName();
   this.variables = variables;
   this.attributes = parseAttributes(node); // 解析屬性
   this.body = parseBody(node); // 解析 body
 }

PropertyParser

`XNode 在解析時調(diào)用了內(nèi)部函數(shù) parseAttributes()parseBody(),這兩個方法內(nèi)部調(diào)用了靜態(tài)方法 PropertyParser#parse 來解析每一個值:

 /**
  * 解析標(biāo)簽對象的屬性
  */
 private Properties parseAttributes(Node n) {
   Properties attributes = new Properties();
   // 遍歷 Node 節(jié)點的屬性
   NamedNodeMap attributeNodes = n.getAttributes();
   if (attributeNodes != null) {
     for (int i = 0; i < attributeNodes.getLength(); i++) {
       Node attribute = attributeNodes.item(i);
       // 使用 PropertyParser 解析占位符值
       String value = PropertyParser.parse(attribute.getNodeValue(), variables);
       attributes.put(attribute.getNodeName(), value);
     }
   }
   return attributes;
 }

PropertyParser#parse 方法內(nèi)部的邏輯如下:

&nbsp;public static String parse(String string, Properties variables) {
&nbsp; &nbsp;// 內(nèi)部類實現(xiàn)的 tokenHandler,支持 ${key:default} 形式的解析
&nbsp; &nbsp;VariableTokenHandler handler = new VariableTokenHandler(variables);
&nbsp; &nbsp;// 使用 GenericTokenParser 來解析占位符屬性
&nbsp; &nbsp;GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
&nbsp; &nbsp;return parser.parse(string);
&nbsp;}

PropertyParser.VariableTokenHandler

靜態(tài)內(nèi)部類,實現(xiàn)了 TokenHandler 接口,該接口用來處理 token 并返回處理后的內(nèi)容。這個實現(xiàn)類支持 ${keyName:default} 這種形式的占位符參數(shù)解析,其中 default 是默認(rèn)值,通過配置來決定是否啟用默認(rèn)值:

 private static class VariableTokenHandler implements TokenHandler {
   private final Properties variables;
   private final boolean enableDefaultValue;
   private final String defaultValueSeparator;
   private VariableTokenHandler(Properties variables) {
     this.variables = variables;
     // 是否啟用了默認(rèn)值,默認(rèn)為 false,該值取自 variables['org.apache.ibatis.parsing.PropertyParser.enable-default-value']
     this.enableDefaultValue = Boolean.parseBoolean(getPropertyValue(KEY_ENABLE_DEFAULT_VALUE, ENABLE_DEFAULT_VALUE));
     // 默認(rèn)值分隔符,默認(rèn)為 ':',該值取自 variables['org.apache.ibatis.parsing.PropertyParser.default-value-separator']
     this.defaultValueSeparator = getPropertyValue(KEY_DEFAULT_VALUE_SEPARATOR, DEFAULT_VALUE_SEPARATOR);
   }
   private String getPropertyValue(String key, String defaultValue) {
     return variables == null ? defaultValue : variables.getProperty(key, defaultValue);
   }
   @Override
   public String handleToken(String content) {
     if (variables != null) {
       String key = content;
       if (enableDefaultValue) {
         // ${key:default} 這樣的表達(dá)式可以支持 default 默認(rèn)值,如果沒有指定的 key 屬性則使用默認(rèn)值
         final int separatorIndex = content.indexOf(defaultValueSeparator);
         String defaultValue = null;
         if (separatorIndex >= 0) {
           // 分隔符之前即為 key
           key = content.substring(0, separatorIndex);
           // 分隔符之后即為默認(rèn)值 default
           defaultValue = content.substring(separatorIndex + defaultValueSeparator.length());
         }
         if (defaultValue != null) {
           return variables.getProperty(key, defaultValue);
         }
       }
       if (variables.containsKey(key)) {
         return variables.getProperty(key);
       }
     }
     // 若沒有找到指定的值,則最終返回配置的原本形式 ${xxx}
     return "${" + content + "}";
   }
 }

GenericTokenParser

該類實現(xiàn)了解析占位符表達(dá)式的具體邏輯。這個類被定義為可以自定義解析方式,而且支持一個字符串中多個占位符參數(shù)的解析,并且該類為 public 類。在項目中若有類似的解析場景需要,可以直接使用該類(但最好復(fù)制該類代碼進(jìn)行客制化修改,防止依賴升級帶來的邏輯不一致出現(xiàn),雖然概率很小)。

該類源碼如下:

 package org.apache.ibatis.parsing;
 public class GenericTokenParser {
   private final String openToken;
   private final String closeToken;
   private final TokenHandler handler;
   public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
     // 可以自定義占位符型式以及具體的參數(shù)解析實現(xiàn)
     this.openToken = openToken;
     this.closeToken = closeToken;
     this.handler = handler;
   }
   public String parse(String text) {
     if (text == null || text.isEmpty()) {
       return "";
     }
     // search open token
     // 占位符屬性一般是 <elem>${xxx}</elem> 或 <elem attr1="${xxx}"/>
     // 但值實際上可以這樣:"I am MRAG from ${userCity:重慶}"
     int start = text.indexOf(openToken);
     if (start == -1) {
       return text;
     }
     char[] src = text.toCharArray();
     // 用來存每次循環(huán)處理的起點下標(biāo)
     int offset = 0;
     // 用來存儲讀過的內(nèi)容
     final StringBuilder builder = new StringBuilder();
     StringBuilder expression = null;
     do {
       if (start > 0 && src[start - 1] == '\') {
         // this open token is escaped. remove the backslash and continue.
         // '{openToken}' 會被認(rèn)為是轉(zhuǎn)義,跳過 '' 并將 '{openToken}' 看做普通字面量
         // 將 [offset, start-1) 區(qū)間的內(nèi)容添加進(jìn) builder,即剛好讀到 '' 之前;然后直接拼接 {openToken}
         builder.append(src, offset, start - offset - 1).append(openToken);
         offset = start + openToken.length(); // offset 移到 {openToken} 之后作為下一次操作起點
       } else {
         // found open token. let's search close token.
         if (expression == null) {
           expression = new StringBuilder();
         } else {
           expression.setLength(0);
         }
         builder.append(src, offset, start - offset); // 將 [offset, start) 區(qū)間的內(nèi)容添加進(jìn) builder
         offset = start + openToken.length(); // 然后移動 offset
         int end = text.indexOf(closeToken, offset); // 然后開始找接著 offset 之后的 closeToken
         while (end > -1) {
           if ((end <= offset) || (src[end - 1] != '\')) {
             // closeToken 沒有被轉(zhuǎn)義的條件是前面沒有反斜杠,或者 closeToken 跟 openToken 連著一起的,即中間沒有參數(shù)
             // 中間沒有參數(shù)的情況,取決于 TokenHandler 如何處理;mybatis 并沒有處理這種情況
             // 理論上如果 properties 含有一個空字符串 key,只要有對應(yīng)的鍵值,就可以處理
             expression.append(src, offset, end - offset); // 將中間的表達(dá)式添加進(jìn) expression
             break;
           }
           // this close token is escaped. remove the backslash and continue.
           expression.append(src, offset, end - offset - 1).append(closeToken);
           offset = end + closeToken.length();
           end = text.indexOf(closeToken, offset);
         }
         if (end == -1) {
           // close token was not found.
           // 找不到配套的 closeToken 就不做處理了,直接當(dāng)字面量處理
           builder.append(src, start, src.length - start);
           offset = src.length;
         } else {
           // 使用 tokenHandler 進(jìn)行轉(zhuǎn)義處理,然后添加進(jìn) builder
           builder.append(handler.handleToken(expression.toString()));
           offset = end + closeToken.length(); // offset 移位
         }
       }
       // 尋找下一個 openToken;找不到就退出循環(huán)
       start = text.indexOf(openToken, offset);
     } while (start > -1);
     if (offset < src.length) {
       // 表達(dá)式后面還有字面量則將字面量添加進(jìn) builder
       builder.append(src, offset, src.length - offset);
     }
     // 處理結(jié)束
     return builder.toString();
   }
 }

該類同時還被多個類使用,比如 SqlSourceBuilderForEachSqlNode、TextSqlNode。mapper 文件中編寫的 sql 使用的參數(shù)占位符、以及直接寫在 @Select @Update 等注解中的 sql,自然也使用了該類來解析。

到此這篇關(guān)于mybatis解析xml配置中${xxx}占位符的代碼邏輯的文章就介紹到這了,更多相關(guān)mybatis ${xxx}占位符內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用Spring Boot集成FastDFS的示例代碼

    使用Spring Boot集成FastDFS的示例代碼

    本篇文章主要介紹了使用Spring Boot集成FastDFS的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • Java中的分布式事務(wù)Seata詳解

    Java中的分布式事務(wù)Seata詳解

    這篇文章主要介紹了Java中的分布式事務(wù)Seata詳解,Seata 是一款開源的分布式事務(wù)解決方案,致力于提供高性能和簡單易用的分布式事務(wù)服務(wù),Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務(wù)模式,為用戶打造一站式的分布式解決方案,需要的朋友可以參考下
    2023-08-08
  • java實現(xiàn)翻轉(zhuǎn)單詞順序列

    java實現(xiàn)翻轉(zhuǎn)單詞順序列

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)翻轉(zhuǎn)單詞順序列,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • 一文秒懂springboot druid 配置

    一文秒懂springboot druid 配置

    Druid是阿里巴巴開發(fā)的一個連接池,他提供了一個高效、功能強(qiáng)大、可擴(kuò)展性好的數(shù)據(jù)庫連接池,區(qū)別于hikari,今天通過本文給大家分享springboot druid 配置教程,需要的朋友參考下吧
    2021-08-08
  • java Zookeeper簡述

    java Zookeeper簡述

    ZooKeeper是一個分布式的,開放源碼的分布式應(yīng)用程序協(xié)調(diào)服務(wù),是Google的Chubby一個開源的實現(xiàn),是Hadoop和Hbase的重要組件。下面通過本文給大家分享java 中 zookeeper簡單使用,需要的朋友參考下吧
    2021-09-09
  • 淺談Java實體對象的三種狀態(tài)以及轉(zhuǎn)換關(guān)系

    淺談Java實體對象的三種狀態(tài)以及轉(zhuǎn)換關(guān)系

    這篇文章主要介紹了淺談Java實體對象的三種狀態(tài)以及轉(zhuǎn)換關(guān)系,具有一定參考價值,需要的朋友可以,看看。。
    2017-11-11
  • JMeter導(dǎo)入自定義的Jar包的詳解教程

    JMeter導(dǎo)入自定義的Jar包的詳解教程

    這篇文章主要介紹了JMeter導(dǎo)入自定義的Jar包的詳解教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • springboot+vue實現(xiàn)oss文件存儲的示例代碼

    springboot+vue實現(xiàn)oss文件存儲的示例代碼

    對象存儲服務(wù)是一種海量、安全、低成本、高可靠的云存儲服務(wù),本文主要介紹了springboot+vue實現(xiàn)oss文件存儲的示例代碼,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • Java中繼承thread類與實現(xiàn)Runnable接口的比較

    Java中繼承thread類與實現(xiàn)Runnable接口的比較

    這篇文章主要介紹了Java中繼承thread類與實現(xiàn)Runnable接口的比較的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • mybatis-plus批處理IService的實現(xiàn)示例

    mybatis-plus批處理IService的實現(xiàn)示例

    這篇文章主要介紹了mybatis-plus批處理IService的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08

最新評論

沈丘县| 凌海市| 长治县| 简阳市| 故城县| 石阡县| 贡山| 临夏县| 大姚县| 临邑县| 梅河口市| 白城市| 剑阁县| 乌鲁木齐县| 蚌埠市| 紫阳县| 孝昌县| 习水县| 阿坝县| 平顶山市| 额尔古纳市| 开原市| 平遥县| 渭源县| 青铜峡市| 迭部县| 天门市| 天镇县| 嘉峪关市| 鄄城县| 江源县| 肇源县| 平山县| 阳朔县| 乌兰察布市| 揭东县| 泸定县| 武穴市| 昌乐县| 平凉市| 镇赉县|