PropertyParser 的工作原理

本文介绍了PropertyParser的工作原理,当配置数据库用户名如${username:root}时,它会在variables中搜索对应值,若未找到则采用默认的'root'。PropertyParser的功能不仅限于默认值解析,还涉及动态SQL语句的解析过程。解析行为由其内部的TokenHandler实现决定。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 *    Copyright 2009-2016 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.parsing;

import java.util.Properties;

/**
 * @author Clinton Begin
 * @author Kazuki Shimizu
 */
public class PropertyParser {
  private static final String KEY_PREFIX = "org.apache.ibatis.parsing.PropertyParser.";
  /**
   * The special property key that indicate whether enable a default value on placeholder.
   * <p>
   *   The default value is {@code false} (indicate disable a default value on placeholder)
   *   If you specify the {@code true}, you can specify key and default value on placeholder (e.g. {@code ${db.username:postgres}}).
   * </p>
   * @since 3.4.2
   */
  //在 mybatis-config.xml 中 <properties >节点下自己置是否开启默认值功能的对应配置项
  public static final String KEY_ENABLE_DEFAULT_VALUE = KEY_PREFIX + "enable-default-value";

  /**
   * The special property key that specify a separator for key and default value on placeholder.
   * <p>
   *   The default separator is {@code ":"}.
   * </p>
   * @since 3.4.2
   */
  //配置 占位符与默认值之间的默认分隔符的对应配置项
  public static final String KEY_DEFAULT_VALUE_SEPARATOR = KEY_PREFIX + "default-value-separator";
  //默认情况下,关闭默认值的功能
  private static final String ENABLE_DEFAULT_VALUE = "false";
  //默认分隔符
  private static final String DEFAULT_VALUE_SEPARATOR = ":";

  private PropertyParser() {
    // Prevent Instantiation
  }

  public static String parse(String string, Properties variables) {
    VariableTokenHandler handler = new VariableTokenHandler(variables);
    //创建 GenericTokenParser对象,并指定其处理的占位符格式为${}
    GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
    return parser.parse(string);
  }

  private static class VariableTokenHandler implements TokenHandler {
    //<properties >节点下定义的键位对,用于替换占位符
    private final Properties variables;
    //是否支持占位符中使用默认值的功能
    private final boolean enableDefaultValue;
    //指定占位符和默认值之间的分隔符
    private final String defaultValueSeparator;

    private VariableTokenHandler(Properties variables) {
      this.variables = variables;
      this.enableDefaultValue = Boolean.parseBoolean(getPropertyValue(KEY_ENABLE_DEFAULT_VALUE, ENABLE_DEFAULT_VALUE));
      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) {
          final int separatorIndex = content.indexOf(defaultValueSeparator);
          String defaultValue = null;
          if (separatorIndex >= 0) {
            //获取占位符名称
            key = content.substring(0, separatorIndex);
            //获取默认值
            defaultValue = content.substring(separatorIndex + defaultValueSeparator.length());
          }
          if (defaultValue != null) {
              //查找指定占位符
            return variables.getProperty(key, defaultValue);
          }
        }
        //如果不支持默认值,直接查询
        if (variables.containsKey(key)) {
          return variables.getProperty(key);
        }
      }
      //如果variables为空,拼接
      return "${" + content + "}";
    }
  }

}

PropertyParser 的工作原理,在该示例中配置的数据库用户名为${usemame:root},其中:是占位符和 默认值的分隔符。 PropertyParser 会在解析后使用
usemame 在 variables 集合中查找相应的值,如果查找不到,则使用 root 作为数据库用户名的默认值 。
GenericTokenParser 不仅仅用于这里的默认值解析,还会用于后面对动态SQL 语句的解析。
GenericTokenParser 只是查找到指定的占位符 ,而具体的解析行为会根据其持有的 TokenHandler 实现的不同而有所不同

java精神(基于函数式组合子逻辑的javaparser框架) 一。 释名。 为什么叫精神? 如果你熟悉c++,那么你可能知道一个叫做”spirit”的parser库。它利用c++的模板元编程能力,使用c++语言本身提供了一个递归下降文法解析的框架。 我这里介绍的jparsec库,就是一个java里面的递归下降文法解析框架。 不过,它并非是spirit的java版本。 Jparsec的蓝本来自Haskell语言的parsec库。Parsec是一个基于monad的parser组合子库。 这个库的目的是要在java中提供一个类似parsec, spirit的库,这种组合子库并非c++的专利,java/c#也可以做到。这个库还将在java5.0上被改写,类型安全上它将也不再逊色于c++。 那么,为什么叫“函数式”呢?java是面向对象的嘛。 如果你使用过haskell, lisp等语言,这个函数式不用解释你也知道是怎么回事了。 如果你是一个老牌的c++/java程序员,那么这里还要稍微解释一下。当然如果您对这些虚头八脑的名词不感兴趣,那么,你尽可以跳过这一章,不知道什么是“函数式”,并不会影响你对这个库的理解的。 C++这几年随着gp的普及,“函数式”这个老孔乙己逐渐又被人从角落里面拽了出来。一个c++程序员所熟悉的“函数式”很可能是stl的for_each, transform,count_if这些函数。 怎么说呢,就象我不能否定str.length()这个调用属于OO一样,我也无法说for_each, transform不是函数式。 但是,“函数式”的精髓不在于此。 一般归纳起来,就像我们说OO是什么多态,封装,继承一样,“函数式”的特征被总结为: 1。无副作用。 2。高阶函数。 3。延迟计算 而最最有意义的(至少我认为如此),是基于高阶函数的函数组合能力。一些人把这叫做glue。 简短地说,什么让函数式编程如此强大?是用简单的函数组合出复杂函数的能力。 我可以想象,说到这里,你还是一头雾水。“什么是组合?1+1不是也把两个1组合成2了吗?new A(new B(), new C())不也是从B和C组合成A了?”
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值