接下来是解析sql语句,对应的是scripting包,实现了动态SQL语句的功能。
LanguageDriver 语言驱动接口
public interface LanguageDriver {
//创建ParameterHandler对象
ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
//创建sqlSource,从xml配置中。
SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
//创建sqlSource,从方法注解配置,即@Select
SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
}
XMLLanguageDriver xml语言驱动实现类
public class XMLLanguageDriver implements LanguageDriver {
@Override
public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
}
@Override
//解析xml文件中的sql语句并封装成SqlSource
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
return builder.parseScriptNode();
}
@Override
public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
//如果是<script>开头就使用xml配置的方法。使用动态SQL
if (script.startsWith("<script>")) {
//创建XPathParser对象解析<script>节点
XPathParser parser = new XPathParser(script, false, configuration.getVariables(), new XMLMapperEntityResolver());
//使用xml配置的解析方式来生成sqlSource
return createSqlSource(configuration, parser.evalNode("/script"), parameterType);
} else {
//变量更换
script = PropertyParser.parse(script, configuration.getVariables());
//创建TextSqlNode对象
TextSqlNode textSqlNode = new TextSqlNode(script);
//如果是动态 SQL ,则创建 DynamicSqlSource 对象
if (textSqlNode.isDynamic()) {
return new DynamicSqlSource(configuration, textSqlNode);
} else {
//如果非动态 SQL ,则创建 RawSqlSource 对象
return new RawSqlSource(configuration, script, parameterType);
}
}
}
}
RawLanguageDriver RawSqlSource 语言驱动器实现类,确保创建的 SqlSource 是 RawSqlSource 类,XMLLanguageDriver的子类
public class RawLanguageDriver extends XMLLanguageDriver {
@Override
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
SqlSource source = super.createSqlSource(configuration, script, parameterType);
//检验创建的是否是RawSqlSource对象
checkIsNotDynamic(source);
return source;
}
@Override
public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
SqlSource source = super.createSqlSource(configuration, script, parameterType);
// 校验创建的是 RawSqlSource 对象
checkIsNotDynamic(source);
return source;
}
//如果是动态sql会抛出异常
private void checkIsNotDynamic(SqlSource source) {
if (!RawSqlSource.class.equals(source.getClass())) {
throw new BuilderException("Dynamic content is not allowed when using RAW language");
}
}
}
LanguageDriverRegistry LanguageDriver 注册表
public class LanguageDriverRegistry {
//LanguageDriver映射
private final Map<Class<? extends LanguageDriver>, LanguageDriver> LANGUAGE_DRIVER_MAP = new HashMap<>();
//默认的 LanguageDriver 类
private Class<? extends LanguageDriver> defaultDriverClass;
//注册类
public void register(Class<? extends LanguageDriver> cls) {
if (cls == null) {
throw new IllegalArgumentException("null is not a valid Language Driver");
}
//判断原来map中没有
if (!LANGUAGE_DRIVER_MAP.containsKey(cls)) {
try {
//将实例放入map
LANGUAGE_DRIVER_MAP.put(cls, cls.newInstance());
} catch (Exception ex) {
throw new ScriptingException("Failed to load language driver for " + cls.getName(), ex);
}
}
}
//注册实例
public void register(LanguageDriver instance) {
if (instance == null) {
throw new IllegalArgumentException("null is not a valid Language Driver");
}
Class<? extends LanguageDriver> cls = instance.getClass();
if (!LANGUAGE_DRIVER_MAP.containsKey(cls)) {
LANGUAGE_DRIVER_MAP.put(cls, instance);
}
}
//获得类对应的实例
public LanguageDriver getDriver(Class<? extends LanguageDriver> cls) {
return LANGUAGE_DRIVER_MAP.get(cls);
}
//获得默认的Driver
public LanguageDriver getDefaultDriver() {
return getDriver(getDefaultDriverClass());
}
public Class<? extends LanguageDriver> getDefaultDriverClass() {
return defaultDriverClass;
}
public void setDefaultDriverClass(Class<? extends LanguageDriver> defaultDriverClass) {
register(defaultDriverClass);
this.defaultDriverClass = defaultDriverClass;
}
}
在Configuration的构造函数中会调用注册方法:
//往map中注册了两个LanguageDriver,其中XMLLanguageDriver是默认的LanguageDriver
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
XMLScriptBuilder 同样继承于BaseBuilder,负责将SQL解析成SqlSource对象
public class XMLScriptBuilder extends BaseBuilder {
//当前SQL的XNode对象
private final XNode context;
//是否为动态SQL
private boolean isDynamic;
//SQL方法类型
private final Class<?> parameterType;
//NodeHandler的映射
private final Map<String, NodeHandler> nodeHandlerMap = new HashMap<>();
public XMLScriptBuilder(Configuration configuration, XNode context) {
this(configuration, context, null);
}
public XMLScriptBuilder(Configuration configuration, XNode context, Class<?> parameterType) {
super(configuration);
this.context = context;
this.parameterType = parameterType;
//初始化nodeHandlerMap 属性
initNodeHandlerMap();
}
//往map中注册各种处理器
private void initNodeHandlerMap() {
nodeHandlerMap.put("trim", new TrimHandler());
nodeHandlerMap.put("where", new WhereHandler());
nodeHandlerMap.put("set", new SetHandler());
nodeHandlerMap.put("foreach", new ForEachHandler());
nodeHandlerMap.put("if", new IfHandler());
nodeHandlerMap.put("choose", new ChooseHandler());
nodeHandlerMap.put("when", new IfHandler());
nodeHandlerMap.put("otherwise", new OtherwiseHandler());
nodeHandlerMap.put("bind", new BindHandler());
}
//解析sql脚本,返回SqlSource
public SqlSource parseScriptNode() {
MixedSqlNode rootSqlNode = parseDynamicTags(context);
SqlSource sqlSource = null;
if (isDynamic) {
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);//动态sql的解析
} else {
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);//非动态sql的解析
}
//实际返回的都是StaticSqlSource,可以直接让数据库执行的sql语句,包含?占位符
return sqlSource;
}
//将SQL解析成MixedSqlNode对象
protected MixedSqlNode parseDynamicTags(XNode node) {
//创建SqlNode数组
List<SqlNode> contents = new ArrayList<>();
//遍历Sql节点的所有子节点
NodeList children = node.getNode().getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
//当前子节点
XNode child = node.newXNode(children.item(i));
//如果类型是文本节点时
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
//获得内容
String data = child.getStringBody("");
//创建TextSqlNode对象
TextSqlNode textSqlNode = new TextSqlNode(data);
//如果是动态的TextSqlNode对象
if (textSqlNode.isDynamic()) {
//添加到contents中
contents.add(textSqlNode);
isDynamic = true;
} else {
//创建静态的TextSqlNode添加到contents中
contents.add(new StaticTextSqlNode(data));
}
//如果是元素节点
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) {
//根据子节点的标签获得对应的NodeHandler对象
String nodeName = child.getNode().getNodeName();
NodeHandler handler = nodeHandlerMap.get(nodeName);
if (handler == null) {
throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
}
//处理NodeHandler对象
handler.handleNode(child, contents);
//标记为动态Sql
isDynamic = true;
}
}
//根据SqlNode数组来创建MixedSqlNode对象
return new MixedSqlNode(contents);
}
//NodeHandler是内部接口,Node处理器接口
private interface NodeHandler {
//处理接口
void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);
}
//<bind>标签的处理器
private class BindHandler implements NodeHandler {
public BindHandler() {
// Prevent Synthetic Access
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
//取出name属性的值
final String name = nodeToHandle.getStringAttribute("name");
//取出value属性的值
final String expression = nodeToHandle.getStringAttribute("value");
// 创建 VarDeclSqlNode 对象
final VarDeclSqlNode node = new VarDeclSqlNode(name, expression);
// 添加到 targetContents 中
targetContents.add(node);
}
}
//
private class TrimHandler implements NodeHandler {
public TrimHandler() {
// Prevent Synthetic Access
}
//<trim>标签的处理器
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
//解析内部的 SQL 节点,成 MixedSqlNode 对象
MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
//获得 prefix、prefixOverrides、suffix、suffixOverrides 属性
String prefix = nodeToHandle.getStringAttribute("prefix");
String prefixOverrides = nodeToHandle.getStringAttribute("prefixOverrides");
String suffix = nodeToHandle.getStringAttribute("suffix");
String suffixOverrides = nodeToHandle.getStringAttribute("suffixOverrides");
//创建TrimSqlNode对象
TrimSqlNode trim = new TrimSqlNode(configuration, mixedSqlNode, prefix, prefixOverrides, suffix, suffixOverrides);
//添加到targetContents中
targetContents.add(trim);
}
}
//处理<where>标签
private class WhereHandler implements NodeHandler {
public WhereHandler() {
// Prevent Synthetic Access
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
//解析内部的SQL节点成MixedSqlNode
MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
//创建WhereSqlNode对象
WhereSqlNode where = new WhereSqlNode(configuration, mixedSqlNode);
targetContents.add(where);
}
}
//处理<set>标签
private class SetHandler implements NodeHandler {
public SetHandler() {
// Prevent Synthetic Access
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
//解析内部的SQL节点成MixedSqlNode对象
MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
// 创建 SetSqlNode 对象
SetSqlNode set = new SetSqlNode(configuration, mixedSqlNode);
targetContents.add(set);
}
}
//<foreach /> 标签的处理器
private class ForEachHandler implements NodeHandler {
public ForEachHandler() {
// Prevent Synthetic Access
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
// 解析内部的 SQL 节点,成 MixedSqlNode 对象
MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
// 获得 collection、item、index、open、close、separator 属性
String collection = nodeToHandle.getStringAttribute("collection");
String item = nodeToHandle.getStringAttribute("item");
String index = nodeToHandle.getStringAttribute("index");
String open = nodeToHandle.getStringAttribute("open");
String close = nodeToHandle.getStringAttribute("close");
String separator = nodeToHandle.getStringAttribute("separator");
// 创建 ForEachSqlNode 对象
ForEachSqlNode forEachSqlNode = new ForEachSqlNode(configuration, mixedSqlNode, collection, index, item, open, close, separator);
targetContents.add(forEachSqlNode);
}
}
//<if /> 标签的处理器
private class IfHandler implements NodeHandler {
public IfHandler() {
// Prevent Synthetic Access
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
// 解析内部的 SQL 节点,成 MixedSqlNode 对象
MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
String test = nodeToHandle.getStringAttribute("test");
// 创建 IfSqlNode 对象
IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
targetContents.add(ifSqlNode);
}
}
//<otherwise /> 标签的处理器
private class OtherwiseHandler implements NodeHandler {
public OtherwiseHandler() {
// Prevent Synthetic Access
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
// 解析内部的 SQL 节点,成 MixedSqlNode 对象
MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
// 添加到 targetContents 中
targetContents.add(mixedSqlNode);
}
}
//<choose /> 标签的处理器
private class ChooseHandler implements NodeHandler {
public ChooseHandler() {
// Prevent Synthetic Access
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
//创建两个list,一个是when属性,一个是otherwise属性
List<SqlNode> whenSqlNodes = new ArrayList<>();
List<SqlNode> otherwiseSqlNodes = new ArrayList<>();
// 解析 `<when />` 和 `<otherwise />` 的节点们
handleWhenOtherwiseNodes(nodeToHandle, whenSqlNodes, otherwiseSqlNodes);
// 获得 `<otherwise />` 的节点
SqlNode defaultSqlNode = getDefaultSqlNode(otherwiseSqlNodes);
// 创建 ChooseSqlNode 对象
ChooseSqlNode chooseSqlNode = new ChooseSqlNode(whenSqlNodes, defaultSqlNode);
// 添加到 targetContents 中
targetContents.add(chooseSqlNode);
}
private void handleWhenOtherwiseNodes(XNode chooseSqlNode, List<SqlNode> ifSqlNodes, List<SqlNode> defaultSqlNodes) {
List<XNode> children = chooseSqlNode.getChildren();
for (XNode child : children) {
String nodeName = child.getNode().getNodeName();
NodeHandler handler = nodeHandlerMap.get(nodeName);
if (handler instanceof IfHandler) {
//处理when的情况
handler.handleNode(child, ifSqlNodes);
} else if (handler instanceof OtherwiseHandler) {
//处理otherwise情况
handler.handleNode(child, defaultSqlNodes);
}
}
}
// 至多允许有一个 SqlNode 节点
private SqlNode getDefaultSqlNode(List<SqlNode> defaultSqlNodes) {
SqlNode defaultSqlNode = null;
if (defaultSqlNodes.size() == 1) {
defaultSqlNode = defaultSqlNodes.get(0);
} else if (defaultSqlNodes.size() > 1) {
throw new BuilderException("Too many default (otherwise) elements in choose statement.");
}
return defaultSqlNode;
}
}
}
DynamicContext 动态SQL,每次执行SQL操作时,记录动态SQL处理后的最终SQL字符串。
public class DynamicContext {
//_parameter的键
public static final String PARAMETER_OBJECT_KEY = "_parameter";
//_databaseId 的键
public static final String DATABASE_ID_KEY = "_databaseId";
static {
//设置OGNL的属性访问器
OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor());
}
//上下文参数集合
private final ContextMap bindings;
//生成后的SQL
private final StringBuilder sqlBuilder = new StringBuilder();
//唯一编号
private int uniqueNumber = 0;
//如果使用到OGNL,ParameterObject为非空
public DynamicContext(Configuration configuration, Object parameterObject) {
if (parameterObject != null && !(parameterObject instanceof Map)) {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
bindings = new ContextMap(metaObject);
} else {
bindings = new ContextMap(null);
}
//添加bindings的默认值
bindings.put(PARAMETER_OBJECT_KEY, parameterObject);
bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());
}
public Map<String, Object> getBindings() {
return bindings;
}
public void bind(String name, Object value) {
bindings.put(name, value);
}
//拼接sql
public void appendSql(String sql) {
sqlBuilder.append(sql);
sqlBuilder.append(" ");
}
//获得sql
public String getSql() {
return sqlBuilder.toString().trim();
}
//每次请求获得新的序号
public int getUniqueNumber() {
return uniqueNumber++;
}
//内部静态类
static class ContextMap extends HashMap<String, Object> {
private static final long serialVersionUID = 2977601501966151582L;
//parameter对应的MetaObject对象
private MetaObject parameterMetaObject;
public ContextMap(MetaObject parameterMetaObject) {
this.parameterMetaObject = parameterMetaObject;
}
@Override
public Object get(Object key) {
String strKey = (String) key;
if (super.containsKey(strKey)) {
return super.get(strKey);
}
if (parameterMetaObject != null) {
// issue #61 do not modify the context when reading
return parameterMetaObject.getValue(strKey);
}
return null;
}
}
//上下文访问器
static class ContextAccessor implements PropertyAccessor {
@Override
public Object getProperty(Map context, Object target, Object name)
throws OgnlException {
Map map = (Map) target;
// 优先从 ContextMap 中,获得属性
Object result = map.get(name);
if (map.containsKey(name) || result != null) {
return result;
}
// 如果没有,则从 PARAMETER_OBJECT_KEY 对应的 Map 中,获得属性
Object parameterObject = map.get(PARAMETER_OBJECT_KEY);
if (parameterObject instanceof Map) {
return ((Map)parameterObject).get(name);
}
return null;
}
@Override
public void setProperty(Map context, Object target, Object name, Object value)
throws OgnlException {
Map<Object, Object> map = (Map<Object, Object>) target;
map.put(name, value);
}
@Override
public String getSourceAccessor(OgnlContext arg0, Object arg1, Object arg2) {
return null;
}
@Override
public String getSourceSetter(OgnlContext arg0, Object arg1, Object arg2) {
return null;
}
}
}
SqlNode SQL Node 接口,每个 XML Node 会解析成对应的 SQL Node 对象
public interface SqlNode {
//应用当前的SQL Node节点
boolean apply(DynamicContext context);
}
VarDeclSqlNode bind标签的实现类
public class VarDeclSqlNode implements SqlNode {
private final String name;
private final String expression;
public VarDeclSqlNode(String var, String exp) {
name = var;
expression = exp;
}
@Override
public boolean apply(DynamicContext context) {
//获得值
final Object value = OgnlCache.getValue(expression, context.getBindings());
//绑定到上下文
context.bind(name, value);
return true;
}
TrimSqlNode trim标签的SqlNode实现类
public class TrimSqlNode implements SqlNode {
//内含的SqlNode节点
private final SqlNode contents;
//前缀
private final String prefix;
//后缀
private final String suffix;
//需要被删除的前缀
private final List<String> prefixesToOverride;
//需要被删除的后缀
private final List<String> suffixesToOverride;
private final Configuration configuration;
//构造函数
public TrimSqlNode(Configuration configuration, SqlNode contents, String prefix, String prefixesToOverride, String suffix, String suffixesToOverride) {
this(configuration, contents, prefix, parseOverrides(prefixesToOverride), suffix, parseOverrides(suffixesToOverride));
}
protected TrimSqlNode(Configuration configuration, SqlNode contents, String prefix, List<String> prefixesToOverride, String suffix, List<String> suffixesToOverride) {
this.contents = contents;
this.prefix = prefix;
this.prefixesToOverride = prefixesToOverride;
this.suffix = suffix;
this.suffixesToOverride = suffixesToOverride;
this.configuration = configuration;
}
@Override
public boolean apply(DynamicContext context) {
//创建FilteredDynamicContext对象
FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);
//执行contents的应用
boolean result = contents.apply(filteredDynamicContext);
//执行FilteredDynamicContext的应用
filteredDynamicContext.applyAll();
return result;
}
//使用|分割字符串成字符串数组并且都转换成大写
private static List<String> parseOverrides(String overrides) {
if (overrides != null) {
final StringTokenizer parser = new StringTokenizer(overrides, "|", false);
final List<String> list = new ArrayList<>(parser.countTokens());
while (parser.hasMoreTokens()) {
list.add(parser.nextToken().toUpperCase(Locale.ENGLISH));
}
return list;
}
return Collections.emptyList();
}
//内部类
private class FilteredDynamicContext extends DynamicContext {
//委托的DynamicContext对象
private DynamicContext delegate;
//prefix是否已经被应用
private boolean prefixApplied;
//suffix是否已经被应用
private boolean suffixApplied;
//StringBuilder对象
private StringBuilder sqlBuffer;
public FilteredDynamicContext(DynamicContext delegate) {
super(configuration, null);
this.delegate = delegate;
this.prefixApplied = false;
this.suffixApplied = false;
this.sqlBuffer = new StringBuilder();
}
public void applyAll() {
//trim去除多余的空格,生成新的sqlBuffer对象
sqlBuffer = new StringBuilder(sqlBuffer.toString().trim());
//将sqlBuffer大写,生成新的trimmedUppercaseSql
String trimmedUppercaseSql = sqlBuffer.toString().toUpperCase(Locale.ENGLISH);
//应用TrimSqlNode的trim逻辑
if (trimmedUppercaseSql.length() > 0) {
applyPrefix(sqlBuffer, trimmedUppercaseSql);
applySuffix(sqlBuffer, trimmedUppercaseSql);
}
//将结果添加到delegate中
delegate.appendSql(sqlBuffer.toString());
}
@Override
public Map<String, Object> getBindings() {
return delegate.getBindings();
}
@Override
public void bind(String name, Object value) {
delegate.bind(name, value);
}
@Override
public int getUniqueNumber() {
return delegate.getUniqueNumber();
}
@Override
public void appendSql(String sql) {
sqlBuffer.append(sql);
}
@Override
public String getSql() {
return delegate.getSql();
}
private void applyPrefix(StringBuilder sql, String trimmedUppercaseSql) {
if (!prefixApplied) {
prefixApplied = true;
if (prefixesToOverride != null) {
//遍历,如果发现开头是指定的prefixtooverride就删除
for (String toRemove : prefixesToOverride) {
if (trimmedUppercaseSql.startsWith(toRemove)) {
sql.delete(0, toRemove.trim().length());
break;
}
}
}
//非空再添加
if (prefix != null) {
sql.insert(0, " ");
sql.insert(0, prefix);
}
}
}
private void applySuffix(StringBuilder sql, String trimmedUppercaseSql) {
if (!suffixApplied) {
suffixApplied = true;
if (suffixesToOverride != null) {
for (String toRemove : suffixesToOverride) {
if (trimmedUppercaseSql.endsWith(toRemove) || trimmedUppercaseSql.endsWith(toRemove.trim())) {
int start = sql.length() - toRemove.trim().length();
int end = sql.length();
sql.delete(start, end);
break;
}
}
}
if (suffix != null) {
sql.append(" ");
sql.append(suffix);
}
}
}
}
}
WhereSqlNode 其实就是TrimSqlNode的一个应用
public class WhereSqlNode extends TrimSqlNode {
private static List<String> prefixList = Arrays.asList("AND ","OR ","AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t");
public WhereSqlNode(Configuration configuration, SqlNode contents) {
super(configuration, contents, "WHERE", prefixList, null, null);
}
}
SetSqlNode 同样的也是TrimSqlNode的一个应用,set标签的实现类
public class SetSqlNode extends TrimSqlNode {
private static List<String> suffixList = Arrays.asList(",");
public SetSqlNode(Configuration configuration,SqlNode contents) {
super(configuration, contents, "SET", null, null, suffixList);
}
}
ForEachSqlBNode foreach标签的实现类
public class ForEachSqlNode implements SqlNode {
public static final String ITEM_PREFIX = "__frch_";
private final ExpressionEvaluator evaluator;
private final String collectionExpression;
private final SqlNode contents;
private final String open;
private final String close;
private final String separator;
//项
private final String item;
//索引
private final String index;
private final Configuration configuration;
//构造函数
public ForEachSqlNode(Configuration configuration, SqlNode contents, String collectionExpression, String index, String item, String open, String close, String separator) {
this.evaluator = new ExpressionEvaluator();
this.collectionExpression = collectionExpression;
this.contents = contents;
this.open = open;
this.close = close;
this.separator = separator;
this.index = index;
this.item = item;
this.configuration = configuration;
}
@Override
public boolean apply(DynamicContext context) {
Map<String, Object> bindings = context.getBindings();
//获得集合iterable对象,用于遍历
final Iterable<?> iterable = evaluator.evaluateIterable(collectionExpression, bindings);
if (!iterable.iterator().hasNext()) {
return true;
}
boolean first = true;
//添加open到sql
applyOpen(context);
int i = 0;
for (Object o : iterable) {
//记录原始的context对象
DynamicContext oldContext = context;
//生成新的context
if (first || separator == null) {
context = new PrefixedContext(context, "");
} else {
context = new PrefixedContext(context, separator);
}
//获得唯一的编号
int uniqueNumber = context.getUniqueNumber();
// Issue #709
//绑定到context
if (o instanceof Map.Entry) {
@SuppressWarnings("unchecked")
Map.Entry<Object, Object> mapEntry = (Map.Entry<Object, Object>) o;
applyIndex(context, mapEntry.getKey(), uniqueNumber);
applyItem(context, mapEntry.getValue(), uniqueNumber);
} else {
applyIndex(context, i, uniqueNumber);
applyItem(context, o, uniqueNumber);
}
//执行contents的应用
contents.apply(new FilteredDynamicContext(configuration, context, index, item, uniqueNumber));
if (first) {
first = !((PrefixedContext) context).isPrefixApplied();
}
context = oldContext;
i++;
}
//添加close到SQL中
applyClose(context);
//移除index和item对应的绑定
context.getBindings().remove(item);
context.getBindings().remove(index);
return true;
}
private void applyIndex(DynamicContext context, Object o, int i) {
if (index != null) {
context.bind(index, o);
context.bind(itemizeItem(index, i), o);
}
}
private void applyItem(DynamicContext context, Object o, int i) {
if (item != null) {
context.bind(item, o);
context.bind(itemizeItem(item, i), o);
}
}
private void applyOpen(DynamicContext context) {
if (open != null) {
context.appendSql(open);
}
}
private void applyClose(DynamicContext context) {
if (close != null) {
context.appendSql(close);
}
}
private static String itemizeItem(String item, int i) {
return ITEM_PREFIX + item + "_" + i;
}
//内部类。实现变量的替换
private static class FilteredDynamicContext extends DynamicContext {
private final DynamicContext delegate;
private final int index;
private final String itemIndex;
private final String item;
public FilteredDynamicContext(Configuration configuration,DynamicContext delegate, String itemIndex, String item, int i) {
super(configuration, null);
this.delegate = delegate;
this.index = i;
this.itemIndex = itemIndex;
this.item = item;
}
@Override
public Map<String, Object> getBindings() {
return delegate.getBindings();
}
@Override
public void bind(String name, Object value) {
delegate.bind(name, value);
}
@Override
public String getSql() {
return delegate.getSql();
}
@Override
public void appendSql(String sql) {
GenericTokenParser parser = new GenericTokenParser("#{", "}", content -> {
//将对于item的访问替换成对于itemizeItem的访问
String newContent = content.replaceFirst("^\\s*" + item + "(?![^.,:\\s])", itemizeItem(item, index));
//将对于itemIndex的访问替换成对于itemizeItem的访问
if (itemIndex != null && newContent.equals(content)) {
newContent = content.replaceFirst("^\\s*" + itemIndex + "(?![^.,:\\s])", itemizeItem(itemIndex, index));
}
return "#{" + newContent + "}";
});
delegate.appendSql(parser.parse(sql));
}
@Override
public int getUniqueNumber() {
return delegate.getUniqueNumber();
}
}
//内部类,支持添加foreach标签中多个元素之间的分隔符的DynamicContext实现类
private class PrefixedContext extends DynamicContext {
private final DynamicContext delegate;
//其实是separator属性
private final String prefix;
//是否已经应用prefix
private boolean prefixApplied;
public PrefixedContext(DynamicContext delegate, String prefix) {
super(configuration, null);
this.delegate = delegate;
this.prefix = prefix;
this.prefixApplied = false;
}
public boolean isPrefixApplied() {
return prefixApplied;
}
@Override
public Map<String, Object> getBindings() {
return delegate.getBindings();
}
@Override
public void bind(String name, Object value) {
delegate.bind(name, value);
}
@Override
public void appendSql(String sql) {
//如果没有应用prefix并且方法参数sql非空,则添加prefix 到 delegate 中
if (!prefixApplied && sql != null && sql.trim().length() > 0) {
delegate.appendSql(prefix);
prefixApplied = true;
}
delegate.appendSql(sql);
}
@Override
public String getSql() {
return delegate.getSql();
}
@Override
public int getUniqueNumber() {
return delegate.getUniqueNumber();
}
}
}
IfSqlNode if标签的SqlNode实现类
public class IfSqlNode implements SqlNode {
private final ExpressionEvaluator evaluator;
//判断表达式
private final String test;
//内嵌的SqlNode节点
private final SqlNode contents;
public IfSqlNode(SqlNode contents, String test) {
this.test = test;
this.contents = contents;
this.evaluator = new ExpressionEvaluator();
}
@Override
public boolean apply(DynamicContext context) {
//判断是否符合条件
if (evaluator.evaluateBoolean(test, context.getBindings())) {
//符合就执行contents的应用
contents.apply(context);
return true;
}
return false;
}
}
ChooseSqlNode choose标签的SqlNode实现类
public class ChooseSqlNode implements SqlNode {
//otherwise对应的SqlNode节点
private final SqlNode defaultSqlNode;
//when标签对应的SqlNode节点数组
private final List<SqlNode> ifSqlNodes;
public ChooseSqlNode(List<SqlNode> ifSqlNodes, SqlNode defaultSqlNode) {
this.ifSqlNodes = ifSqlNodes;
this.defaultSqlNode = defaultSqlNode;
}
@Override
public boolean apply(DynamicContext context) {
//逐个调用when标签,如果有就进行应用,但是只应用一个SqlNode对象
for (SqlNode sqlNode : ifSqlNodes) {
if (sqlNode.apply(context)) {
return true;
}
}
//再判断otherwise是否存在
if (defaultSqlNode != null) {
defaultSqlNode.apply(context);
return true;
}
return false;
}
}

被折叠的 条评论
为什么被折叠?



