一、前言
DynamicContext(在scripting.xmltags包)里面封装了静态内部类ContextMap,并且ContextMap作为DynamicContext的成员变量bindings,用于封装用户入参parameterObject的。在《成员变量的作用》一节有讲到,bindings成员变量这里装载数据作用,关于存数据这里DynamicContext封装了bind()方法;
二、MyBatis的ContextMap实现HashMap重写get方法
MetaObject封装用户入参parameterObject
MetaObject metaObject = configuration.newMetaObject(parameterObject); ContextMap封装MetaObject,间接就是封装了用户入参parameterObject bindings = new ContextMap(metaObject, existsTypeHandler);
为了方便理解,ContextMap也可以理解为一种数据库的作用只是没有持久化,下面就把ContextMap当作数据库看待。而用ContextMap继承HashMap,是因为HashMap的get方法没有满足需求。因为value可能不在HashMap里面,可能存在parameterMetaObjec里面,也可能NULL。
1、ContextMap的get方法(完整源码请看下面DynamicContext完整源码)
// 这里好比分表,HashMap是一个表,parameterMetaObject另一个表,一个个获取,也可能返回空。可能比喻不是很恰当
@Override
public Object get(Object key) {
String strKey = (String) key;
// 判断数据库是否有了该数据
if (super.containsKey(strKey)) {
return super.get(strKey);
}
// 数据库没有数据,判断parameterMetaObject是否空
if (parameterMetaObject == null) {
return null;
}
// 上面parameterMetaObject非空,这里调用方法就不会出现NULL异常了
if (fallbackParameterObject && !parameterMetaObject.hasGetter(strKey)) {
return parameterMetaObject.getOriginalObject();
} else {
// issue #61 do not modify the context when reading
return parameterMetaObject.getValue(strKey);
}
}
2、DynamicContext完整源码
/**
* 记录 动态SQL语句解析结果的 容器
* @author Clinton Begin
*/
public class DynamicContext {
public static final String PARAMETER_OBJECT_KEY = "_parameter";
public static final String DATABASE_ID_KEY = "_databaseId";
static {
OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor());
}
private final ContextMap bindings; // 参数上下文,内部类成员变量,实现HashMap并重写get()方法
// 在SqlNode解析动态SQL时,会将解析后的SQL语句片段添加到该属性中保存,最终拼凑出一条完整的SQL语句
private final StringJoiner sqlBuilder = new StringJoiner(" ");
private int uniqueNumber = 0;
/**
* 公有构造方法 职责是:初始化bindings集合
* @param configuration
* @param parameterObject 用户传入的实参
*/
public DynamicContext(Configuration configuration, Object parameterObject) {
// 参数不为空,为空后面会不会报错????
if (parameterObject != null && !(parameterObject instanceof Map)) {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
boolean existsTypeHandler = configuration
.getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass());
bindings = new ContextMap(metaObject, existsTypeHandler);
} else {
bindings = new ContextMap(null, false);
}
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);
}
public void appendSql(String sql) {
sqlBuilder.add(sql);
}
public String getSql() {
return sqlBuilder.toString().trim();
}
public int getUniqueNumber() {
return uniqueNumber++;
}
// 静态内部类,继承HashMap
static class ContextMap extends HashMap<String, Object> {
private static final long serialVersionUID = 2977601501966151582L;
private final MetaObject parameterMetaObject;
private final boolean fallbackParameterObject;
/**
* 公有构造方法,构造初始化自己的成员变量
* @param parameterMetaObject
* @param fallbackParameterObject
*/
public ContextMap(MetaObject parameterMetaObject, boolean fallbackParameterObject) {
this.parameterMetaObject = parameterMetaObject;
this.fallbackParameterObject = fallbackParameterObject;
}
@Override
public Object get(Object key) {
String strKey = (String) key;
// 判断数据库是否有了该数据
if (super.containsKey(strKey)) {
return super.get(strKey);
}
// 数据库没有数据,判断parameterMetaObject是否空
if (parameterMetaObject == null) {
return null;
}
// 上面parameterMetaObject非空,这里调用方法就不会出现NULL异常了
if (fallbackParameterObject && !parameterMetaObject.hasGetter(strKey)) {
return parameterMetaObject.getOriginalObject();
} else {
// issue #61 do not modify the context when reading
return parameterMetaObject.getValue(strKey);
}
}
}
}
如果对你有帮助,就点点赞,不要白嫖人家啦!!!讨厌!!
|