一、占位符解析器源码

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. mq(1):简介

    1.mq的使用场景 以前的我,一直都没太搞明白,为什么我们那么需要消息队列,直到我看到了网友scienjus.的这个例子. 例子:假设用户在你的软件中注册,服务端收到用户的注册请求后,它会做这些操作: ...

  2. TTL特殊门电路

    集电极开路(OC)门:主要作用实现线与功能:用做驱动器:实现电平转换 三态输出(TS)门:应用于计算机总线结构,通过分时控制三态门始轮端使得cpu与不同的外设通信:应用于双向传输,实现门电路与总线实现 ...

  3. 向量空间模型(VSM)在文档相似度计算上的简单介绍

    C#实现在: http://blog.csdn.net/Felomeng/archive/2009/03/25/4023990.aspx 向量空间模型(VSM:Vector space model)是 ...

  4. Ansible-playbook的简单使用 [转]

    一. 介绍 ansbile-playbook是一系列ansible命令的集合,利用yaml 语言编写.playbook命令根据自上而下的顺序依次执行.同时,playbook开创了很多特性,它可以允许你 ...

  5. L312 难看懂的

    There are few sadder sights than 8 pile of fan letters ,lovingly decorated with hand drawings,suffer ...

  6. L266 作文

     With the rapid development of modem society, an increasing number of people are concerned about the ...

  7. mysql 数据库关于增加用户权限的问题

    一新建用户 ----------- 二首先修改权限必须在电脑cmd 中运行 开设的权限  主要就是 1 所有库的  *.*      2  所有的表   db.*      3所有的字段db.t1   ...

  8. python3自学第二天,模块,三元运算

    1.模块的认识. sys模块,os模块等 如何引入模块 import os cmd_res1=os.system("dir") # 执行命令dir,不保存结果 print(cmd_ ...

  9. python day02 作业答案

    1. (1).false   (2).false 2. (1).8  (2).4 3. (1).6  (2).3  (3).false (4).3   (5).true   (6).true  (7) ...

  10. SQL注入之Sqli-labs系列第一关

    在开始接触渗透测试开始,最初玩的最多的就是Sql注入,注入神器阿D.明小子.穿山甲等一切工具风靡至今.当初都是以日站为乐趣,从安全法实施后在没有任何授权的情况下,要想练手只能本地环境进行练手,对于sq ...