ssioneva luator eva luator;
private final String test;
private final SqlNode contents;
public IfSqlNode(SqlNode contents, String test) {
this.test = test;
this.contents = contents;
this.eva luator = new Expressioneva luator();
}
@Override
public boolean apply(DynamicContext context) {
// OGNL执行test语句
if (eva luator.eva luateBoolean(test, context.getBindings())) {
contents.apply(context);
return true;
}
return false;
}
}
Expressioneva luator使用的是OGNL表达式来运算的。
再举一个高级的例子:ForEachSqlNode,其中包括对数组和Collection以及Map的解析,核心是通过OGNL获取对应的迭代器:
final Iterable<?> iterable = eva luator.eva luateIterable(collectionExpression, bindings);
public Iterable<?> eva luateIterable(String expression, Object parameterObject) {
Object value = OgnlCache.getValue(expression, parameterObject);
if (value == null) {
throw new BuilderException("The expression '" + expression + "' eva luated to a null value.");
}
if (value instanceof Iterable) {
return (Iterable<?>) value;
}
if (value.getClass().isArray()) {
// the array may be primitive, so Arrays.asList() may throw
// a ClassCastException (issue 209). Do the work manually
// Curse primitives! :) (JGB)
int size = Array.getLength(value);
List<Object> answer = new ArrayList<Object>();
// 数组为何要这样处理?参考后记1
for (int i = 0; i < size; i++) {
Object o = Array.get(value, i);
answer.add(o);
}
return answer;
}
if (value instanceof Map) {
return ((Map) value).entrySet();
}
throw new BuilderException("Error eva luating expression '" + expression + "'. Return value (" + value + ") was not iterable.");
}
中间有个有意思的注释,参考后记1.
第二部分 ${},#{}的解析
首先需要明确:
- ${}: 使用OGNL动态执行内容,结果拼在SQL中
- #{}: 作为参数标记符解析,把解析内容作为prepareStatement的参数。
对于xml标签,其中的表达式也是使用的${}的解析方式,使用OGNL表达式来解析。
对于参数标记符解析,mybatis使用的是自己设计的解析器,使用反射机制获取各种属性。
以#{bean.property}为例,使用反射取到bean的属性property值。他的解析过程如下:
- BaseExecutor.createCacheKey方法
这个方法中遍历解析所有的参数映射关系,并根据#{propertyName}中的propertyName值来获取参数的具体值
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
CacheKey cacheKey = new CacheKey();
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
// mimic DefaultParameterHandler logic
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
// 第二步
MetaObject metaObject = configuration.newMetaObject(parameterObject);
// 第四步
value = metaObject.getValue(propertyName);
}
cacheK