一、占位符解析器源码

1、占位符解析器实现的目标

通过解析字符串中指定前后缀中的字符,并完成相应的功能。

在mybtias中的应用,主要是为了解析Mapper的xml中的sql语句#{}中的内容,识别当前sql语句的一些特性。

2、占位符解析器的通用算法类

(1)org.apache.ibatis.parsing.GenericTokenParser

public class GenericTokenParser {

  private final String openToken;
private final String closeToken;
private final TokenHandler handler; public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
this.openToken = openToken;
this.closeToken = closeToken;
this.handler = handler;
} public String parse(String text) {
final StringBuilder builder = new StringBuilder();
final StringBuilder expression = new StringBuilder();
if (text != null && text.length() > 0) {
char[] src = text.toCharArray();
int offset = 0;
// search open token
int start = text.indexOf(openToken, offset);
while (start > -1) {
if (start > 0 && src[start - 1] == '\\') {
// this open token is escaped. remove the backslash and continue.
builder.append(src, offset, start - offset - 1).append(openToken);
offset = start + openToken.length();
} else {
// found open token. let's search close token.
expression.setLength(0);
builder.append(src, offset, start - offset);
offset = start + openToken.length();
int end = text.indexOf(closeToken, offset);
while (end > -1) {
if (end > offset && src[end - 1] == '\\') {
// 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);
} else {
expression.append(src, offset, end - offset);
offset = end + closeToken.length();
break;
}
}
if (end == -1) {
// close token was not found.
builder.append(src, start, src.length - start);
offset = src.length;
} else {
builder.append(handler.handleToken(expression.toString()));
offset = end + closeToken.length();
}
}
start = text.indexOf(openToken, offset);
}
if (offset < src.length) {
builder.append(src, offset, src.length - offset);
}
}
return builder.toString();
}
}

解析占位符中的字符串的接口类

(2)org.apache.ibatis.parsing.TokenHandler

public interface TokenHandler {
String handleToken(String content);
}

(3)解析sql语句中的参数绑定的tokenHandler的实现类

org.apache.ibatis.builder.ParameterMappingTokenHandler

/**
* Copyright 2009-2015 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.builder; import java.util.ArrayList;
import java.util.List;
import java.util.Map; import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.parsing.GenericTokenParser;
import org.apache.ibatis.parsing.TokenHandler;
import org.apache.ibatis.reflection.MetaClass;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType; /**
* @author Clinton Begin
*/
public class SqlSourceBuilder extends BaseBuilder { private static final String parameterProperties = "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName"; public SqlSourceBuilder(Configuration configuration) {
super(configuration);
} public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
String sql = parser.parse(originalSql);
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
} private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler { private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
private Class<?> parameterType;
private MetaObject metaParameters; public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType, Map<String, Object> additionalParameters) {
super(configuration);
this.parameterType = parameterType;
this.metaParameters = configuration.newMetaObject(additionalParameters);
} public List<ParameterMapping> getParameterMappings() {
return parameterMappings;
} @Override
public String handleToken(String content) {
parameterMappings.add(buildParameterMapping(content));
return "?";
} private ParameterMapping buildParameterMapping(String content) {
Map<String, String> propertiesMap = parseParameterMapping(content);
String property = propertiesMap.get("property");
Class<?> propertyType;
if (metaParameters.hasGetter(property)) { // issue #448 get type from additional params
propertyType = metaParameters.getGetterType(property);
} else if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
propertyType = parameterType;
} else if (JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType"))) {
propertyType = java.sql.ResultSet.class;
} else if (property != null) {
MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());
if (metaClass.hasGetter(property)) {
propertyType = metaClass.getGetterType(property);
} else {
propertyType = Object.class;
}
} else {
propertyType = Object.class;
}
ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
Class<?> javaType = propertyType;
String typeHandlerAlias = null;
for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
String name = entry.getKey();
String value = entry.getValue();
if ("javaType".equals(name)) {
javaType = resolveClass(value);
builder.javaType(javaType);
} else if ("jdbcType".equals(name)) {
builder.jdbcType(resolveJdbcType(value));
} else if ("mode".equals(name)) {
builder.mode(resolveParameterMode(value));
} else if ("numericScale".equals(name)) {
builder.numericScale(Integer.valueOf(value));
} else if ("resultMap".equals(name)) {
builder.resultMapId(value);
} else if ("typeHandler".equals(name)) {
typeHandlerAlias = value;
} else if ("jdbcTypeName".equals(name)) {
builder.jdbcTypeName(value);
} else if ("property".equals(name)) {
// Do Nothing
} else if ("expression".equals(name)) {
throw new BuilderException("Expression based parameters are not supported yet");
} else {
throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content + "}. Valid properties are " + parameterProperties);
}
}
if (typeHandlerAlias != null) {
builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
}
return builder.build();
} private Map<String, String> parseParameterMapping(String content) {
try {
return new ParameterExpression(content);
} catch (BuilderException ex) {
throw ex;
} catch (Exception ex) {
throw new BuilderException("Parsing error was found in mapping #{" + content + "}. Check syntax #{property|(expression), var1=value1, var2=value2, ...} ", ex);
}
}
} }
#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

其功能时将xml中配置的sql语句里"#{", "}"中间的字符串,知道该sql语句中的参数信息

1、参数在mapp接口入参的bean的属性名

2、该属性是什么数据类型

3、在数据库中映射成什么jdbc类型

4、参数转换的TypeHandler的类信息

二、策略模式的应用

https://www.cnblogs.com/shangxiaofei/p/5146107.html

将不同的算法独立封装。

新增或减少算法,对使用算法者无影响。

不同的场景使用不同的算法。

【mybatis源码学习】mybtias基础组件-占位符解析器的更多相关文章

  1. Mybatis源码学习第六天(核心流程分析)之Executor分析

    今Executor这个类,Mybatis虽然表面是SqlSession做的增删改查,其实底层统一调用的是Executor这个接口 在这里贴一下Mybatis查询体系结构图 Executor组件分析 E ...

  2. Mybatis源码学习之parsing包(解析器)(二)

    简述 大家都知道mybatis中,无论是配置文件mybatis-config.xml,还是SQL语句,都是写在XML文件中的,那么mybatis是如何解析这些XML文件呢?这就是本文将要学习的就是,m ...

  3. mybatis源码学习:一级缓存和二级缓存分析

    目录 零.一级缓存和二级缓存的流程 一级缓存总结 二级缓存总结 一.缓存接口Cache及其实现类 二.cache标签解析源码 三.CacheKey缓存项的key 四.二级缓存TransactionCa ...

  4. mybatis源码学习:基于动态代理实现查询全过程

    前文传送门: mybatis源码学习:从SqlSessionFactory到代理对象的生成 mybatis源码学习:一级缓存和二级缓存分析 下面这条语句,将会调用代理对象的方法,并执行查询过程,我们一 ...

  5. mybatis源码学习(一) 原生mybatis源码学习

    最近这一周,主要在学习mybatis相关的源码,所以记录一下吧,算是一点学习心得 个人觉得,mybatis的源码,大致可以分为两部分,一是原生的mybatis,二是和spring整合之后的mybati ...

  6. mybatis源码学习:插件定义+执行流程责任链

    目录 一.自定义插件流程 二.测试插件 三.源码分析 1.inteceptor在Configuration中的注册 2.基于责任链的设计模式 3.基于动态代理的plugin 4.拦截方法的interc ...

  7. Spring源码解析之PropertyPlaceholderHelper(占位符解析器)

    Spring源码解析之PropertyPlaceholderHelper(占位符解析器) https://blog.csdn.net/weixin_39471249/article/details/7 ...

  8. spring占位符解析器---PropertyPlaceholderHelper

    一.PropertyPlaceholderHelper 职责 扮演者占位符解析器的角色,专门用来负责解析路劲中or名字中的占位符的字符,并替换上具体的值 二.例子 public class Prope ...

  9. Mybatis源码学习之整体架构(一)

    简述 关于ORM的定义,我们引用了一下百度百科给出的定义,总体来说ORM就是提供给开发人员API,方便操作关系型数据库的,封装了对数据库操作的过程,同时提供对象与数据之间的映射功能,解放了开发人员对访 ...

随机推荐

  1. 遍历所有子物体中renderer(渲染器)中的material(材质)

    //得到所有可渲染的子物体Renderer[] rds = transform.GetComponentsInChildren<Renderer>();//逐一遍历他的子物体中的Rende ...

  2. mysql 从库执行insert失败导致同步停止

    服务配置:一主一从,版本都是 5.5 .主库配置了 binlog-do-db binlog-ignore-db 问题复述:运营人员发现,昨天的数据统计不对.数据分析服务查询的是从库的数据. 到tomc ...

  3. EF-记录程序自动生成并执行的sql语句日志

    在EntityFramework的CodeFirst模式中,我们想将程序自动生成的sql语句和执行过程记录到日志中,方便以后查看和分析. 在EF的6.x版本中,在DbContext中有一个Databa ...

  4. 理解JavaScript的运行

    JavaScript可以运行在head和body标签中! HTML的脚本必须放在<script></script>标签中间! 浏览器会解释并执行位于script标签中的脚本! ...

  5. Cracking The Coding Interview 4.0_二叉树

    #include <iostream> #include <string> using namespace std; class tree { public: tree() { ...

  6. Xilinx FPGA复位逻辑处理小结(转)

    Xilinx FPGA复位逻辑处理小结 1. 为什么要复位呢? (1)FPGA上电的时候对设计进行初始化: (2)使用一个外部管脚来实现全局复位,复位作为一个同步信号将所有存储单元设置为一个已知的状态 ...

  7. Centos7部署Flannel网络(八)

    1.为Flannel生成证书 [root@linux-node1 ssl]# vim flanneld-csr.json { "CN": "flanneld", ...

  8. Java语法基础学习DaySeven

    ---恢复内容开始--- 一.包装类——Wrapper 1.定义:针对八种基本数据类型定义相应的引用类型——包装类(封装类) boolean——Boolean          byte——Byte ...

  9. C++中的break,continue和return语句小结

    1.break语句能用在switch,while,do...while和for语句中:continue语句用在while,do...while和for语句中. 2.break结束语句执行,并将程序的执 ...

  10. TestNG参数化测试-数据提供程序 @DataProvider方式

    在 testng.xml 中指定参数可能会有如下的不足: 1.如果你压根不用 testng.xml. 2.你需要传递复杂的参数,或者从Java中创建参数(复杂对象,对象从属性文件或者数据库中读取的et ...