欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

XNode

mybatis 在解析節(jié)點(diǎn)時(shí)使用的是 w3c 提供的 XML 解析工具,其類型為 org.w3c.dom.Node;但 mybatis 會(huì)使用 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 在解析時(shí)調(diào)用了內(nèi)部函數(shù) parseAttributes()parseBody(),這兩個(gè)方法內(nèi)部調(diào)用了靜態(tài)方法 PropertyParser#parse 來(lái)解析每一個(gè)值:

 /**
  * 解析標(biāo)簽對(duì)象的屬性
  */
 private Properties parseAttributes(Node n) {
   Properties attributes = new Properties();
   // 遍歷 Node 節(jié)點(diǎn)的屬性
   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)部類實(shí)現(xiàn)的 tokenHandler,支持 ${key:default} 形式的解析
&nbsp; &nbsp;VariableTokenHandler handler = new VariableTokenHandler(variables);
&nbsp; &nbsp;// 使用 GenericTokenParser 來(lái)解析占位符屬性
&nbsp; &nbsp;GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
&nbsp; &nbsp;return parser.parse(string);
&nbsp;}

PropertyParser.VariableTokenHandler

靜態(tài)內(nèi)部類,實(shí)現(xiàn)了 TokenHandler 接口,該接口用來(lái)處理 token 并返回處理后的內(nèi)容。這個(gè)實(shí)現(xiàn)類支持 ${keyName:default} 這種形式的占位符參數(shù)解析,其中 default 是默認(rèn)值,通過(guò)配置來(lái)決定是否啟用默認(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)值,如果沒(méi)有指定的 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);
       }
     }
     // 若沒(méi)有找到指定的值,則最終返回配置的原本形式 ${xxx}
     return "${" + content + "}";
   }
 }

GenericTokenParser

該類實(shí)現(xiàn)了解析占位符表達(dá)式的具體邏輯。這個(gè)類被定義為可以自定義解析方式,而且支持一個(gè)字符串中多個(gè)占位符參數(shù)的解析,并且該類為 public 類。在項(xiàng)目中若有類似的解析場(chǎng)景需要,可以直接使用該類(但最好復(fù)制該類代碼進(jìn)行客制化修改,防止依賴升級(jí)帶來(lái)的邏輯不一致出現(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ù)解析實(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}"/>
     // 但值實(shí)際上可以這樣:"I am MRAG from ${userCity:重慶}"
     int start = text.indexOf(openToken);
     if (start == -1) {
       return text;
     }
     char[] src = text.toCharArray();
     // 用來(lái)存每次循環(huán)處理的起點(diǎn)下標(biāo)
     int offset = 0;
     // 用來(lái)存儲(chǔ)讀過(guò)的內(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}' 會(huì)被認(rèn)為是轉(zhuǎn)義,跳過(guò) '' 并將 '{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} 之后作為下一次操作起點(diǎn)
       } 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(); // 然后移動(dòng) offset
         int end = text.indexOf(closeToken, offset); // 然后開(kāi)始找接著 offset 之后的 closeToken
         while (end > -1) {
           if ((end <= offset) || (src[end - 1] != '\')) {
             // closeToken 沒(méi)有被轉(zhuǎn)義的條件是前面沒(méi)有反斜杠,或者 closeToken 跟 openToken 連著一起的,即中間沒(méi)有參數(shù)
             // 中間沒(méi)有參數(shù)的情況,取決于 TokenHandler 如何處理;mybatis 并沒(méi)有處理這種情況
             // 理論上如果 properties 含有一個(gè)空字符串 key,只要有對(duì)應(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 移位
         }
       }
       // 尋找下一個(gè) 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();
   }
 }

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

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

相關(guān)文章

  • 如何使用Spring AOP預(yù)處理Controller的參數(shù)

    如何使用Spring AOP預(yù)處理Controller的參數(shù)

    這篇文章主要介紹了如何使用Spring AOP預(yù)處理Controller的參數(shù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java根據(jù)URL下載文件到本地的2種方式(大型文件與小型文件)

    Java根據(jù)URL下載文件到本地的2種方式(大型文件與小型文件)

    這篇文章主要給大家介紹了關(guān)于Java根據(jù)URL下載文件到本地的2種方式,分別是大型文件與小型文件,避免內(nèi)存溢出OOM,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • SpringBoot使用自動(dòng)配置xxxAutoConfiguration

    SpringBoot使用自動(dòng)配置xxxAutoConfiguration

    這篇文章介紹了SpringBoot自動(dòng)配置xxxAutoConfiguration的使用方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • java獲取linux服務(wù)器上的IP操作

    java獲取linux服務(wù)器上的IP操作

    這篇文章主要介紹了java獲取linux服務(wù)器上的IP操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • 使用spring配置文件.xml的頭文件

    使用spring配置文件.xml的頭文件

    這篇文章主要介紹了使用spring配置文件.xml的頭文件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • java實(shí)現(xiàn)微信支付結(jié)果通知

    java實(shí)現(xiàn)微信支付結(jié)果通知

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信支付結(jié)果通知,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 基于紅黑樹(shù)插入操作原理及java實(shí)現(xiàn)方法(分享)

    基于紅黑樹(shù)插入操作原理及java實(shí)現(xiàn)方法(分享)

    下面小編就為大家分享一篇基于紅黑樹(shù)插入操作原理及java實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • SpringBoot?如何通過(guò)?Profile?實(shí)現(xiàn)不同環(huán)境下的配置切換

    SpringBoot?如何通過(guò)?Profile?實(shí)現(xiàn)不同環(huán)境下的配置切換

    SpringBoot通過(guò)profile實(shí)現(xiàn)在不同環(huán)境下的配置切換,比如常見(jiàn)的開(kāi)發(fā)環(huán)境、測(cè)試環(huán)境、生產(chǎn)環(huán)境,SpringBoot常用配置文件主要有?2?種:properties?文件和yml文件,本文給大家詳細(xì)介紹SpringBoot?通過(guò)?Profile?實(shí)現(xiàn)不同環(huán)境下的配置切換,感興趣的朋友一起看看吧
    2022-08-08
  • java.util.NoSuchElementException原因及兩種解決方法

    java.util.NoSuchElementException原因及兩種解決方法

    本文主要介紹了java.util.NoSuchElementException原因及兩種解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • springmvc接收參數(shù)為日期類型詳解

    springmvc接收參數(shù)為日期類型詳解

    這篇文章主要介紹了springmvc接收參數(shù)為日期類型,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09

最新評(píng)論