设为首页 加入收藏

TOP

MyBatis 解析 XML 标签及占位符相关源码剖析(二)
2018-04-08 08:51:29 】 浏览:802
Tags:MyBatis 解析 XML 标签 占位 相关 源码 剖析
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.

第二部分 ${},#{}的解析

首先需要明确:

  1. ${}: 使用OGNL动态执行内容,结果拼在SQL中
  2. #{}: 作为参数标记符解析,把解析内容作为prepareStatement的参数。

对于xml标签,其中的表达式也是使用的${}的解析方式,使用OGNL表达式来解析。

对于参数标记符解析,mybatis使用的是自己设计的解析器,使用反射机制获取各种属性。

以#{bean.property}为例,使用反射取到bean的属性property值。他的解析过程如下:

  1. 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
首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java日志框架:logback详解 下一篇一次非典型性 Redis 阻塞总结

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目