`

MyBatis原理(2)-执行流程 1 BoundSql生成

 
阅读更多
MyBatis执行两种方式:
1.
	SqlSession openSession = sqlSessionFactory.openSession();
		Dept d = new Dept();
		d.setId(1506720);
		Object dept = openSession.selectOne("dao.DeptDAO1.select",d);
		System.out.println(dept);

2.
DeptMapper mapper = openSession.getMapper(DeptMapper.class);
		Dept dept2= mapper.select(d);
		System.out.println(dept2);


方式1:
1.DefaultSqlSessionFactory
  @Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

 public ExecutorType getDefaultExecutorType() {
    return defaultExecutorType;
  }
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

public enum ExecutorType {
  SIMPLE, REUSE, BATCH
}

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
     //XMLConfigBuilder#environmentsElement加载
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
       //新建一个事务
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }


Configuration#newExecutor 生成相应的Executor


 
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
   //缓存
    if (cacheEnabled) {
     //后面统一分析Executor集合和其子类,这里将SimpleExecutor包装为一个 
     //CachingExecutor
      executor = new CachingExecutor(executor);
    }
    //调用拦截器链中注册的拦截器(如果拦截类型是Executor),每个拦截器会对当前
   //Executor进行动态代理,如果有n个拦截器拦截Executor,会生成对Executor的n层代理, 
  //后面再进行详细分析
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

SqlSession构造完毕后执行selectOne方法:
  @Override
  public <T> T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    List<T> list = this.<T>selectList(statement, parameter);
    if (list.size() == 1) {
      return list.get(0);
    } else if (list.size() > 1) {
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }


RowBounds //TODO
继续调用重载的selectList
  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
//包装参数为StrictMap
private Object wrapCollection(final Object object) {
    if (object instanceof Collection) {
      StrictMap<Object> map = new StrictMap<Object>();
      map.put("collection", object);
      if (object instanceof List) {
        map.put("list", object);
      }
      return map;
    } else if (object != null && object.getClass().isArray()) {
      StrictMap<Object> map = new StrictMap<Object>();
      map.put("array", object);
      return map;
    }
    return object;
  }


DefaultSqlSession //TODO
执行Executor的query方法:
 @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    //获取带?号的sql和参数映射
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

MapperStatement#getBoundSql
public BoundSql getBoundSql(Object parameterObject) {
    //调用SqlSource的getBoundSql,这里的sqlSource是DymicSqlSource的一个实例
   //见前一篇文章XMLScriptBuilder#parseScriptNode
  //  sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    //如果参数映射为空才考虑使用ParameterMap
   //ParameterMap在mapper解析 insert update select 等标签时生成
    if (parameterMappings == null || parameterMappings.isEmpty()) {
      boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
    }

      //检查ParameterMap是否有嵌套的ResultMap
    // check for nested result maps in parameter mappings (issue #30)
    for (ParameterMapping pm : boundSql.getParameterMappings()) {
      String rmId = pm.getResultMapId();
      if (rmId != null) {
        ResultMap rm = configuration.getResultMap(rmId);
        if (rm != null) {
          hasNestedResultMaps |= rm.hasNestedResultMaps();
        }
      }
    }

    return boundSql;
  }


 //SqlSource一共有四个子类:ProviderSqlSource,DynamicSqlSource、RawSqlSource、StaticSqlSource
public class DynamicSqlSource implements SqlSource {

  private final Configuration configuration;
  private final SqlNode rootSqlNode;

  public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
    this.configuration = configuration;
    this.rootSqlNode = rootSqlNode;
  }

  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    rootSqlNode.apply(context);
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
      boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
    }
    return boundSql;
  }

}

DynamicContext:
public class DynamicContext {

  public static final String PARAMETER_OBJECT_KEY = "_parameter";
  public static final String DATABASE_ID_KEY = "_databaseId";

  static {
     //初始化OgnlRuntime使用ContextAccessor作为访问器
    OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor());
  }

  private final ContextMap bindings;
  private final StringBuilder sqlBuilder = new StringBuilder();
  private int uniqueNumber = 0;
   //如果当前参数是实体对象或者List的子类等其他对象,反正不是Map
  
  public DynamicContext(Configuration configuration, Object parameterObject) {
    //当前参数不是map的实例
    if (parameterObject != null && !(parameterObject instanceof Map)) {
      MetaObject metaObject = configuration.newMetaObject(parameterObject);
      bindings = new ContextMap(metaObject);
    } else {
       //为空或者是Map
      bindings = new ContextMap(null);
    }
    //将对象参数放入 key为_parameter的map中
    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.append(sql);
    sqlBuilder.append(" ");
  }

  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;

    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中的keyvalue或者获取MetaObject中的getValue
      Object result = map.get(name);
      if (map.containsKey(name) || result != null) {
        return result;
      }
     //如参数对象本身是个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;
    }
  }
}

Configuration#newMetaObject

  public MetaObject newMetaObject(Object object) {
    return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
  }

MetaObject:
public class MetaObject {

  private final Object originalObject;
  private final ObjectWrapper objectWrapper;
  private final ObjectFactory objectFactory;
  private final ObjectWrapperFactory objectWrapperFactory;
  private final ReflectorFactory reflectorFactory;

  private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    this.originalObject = object;
    this.objectFactory = objectFactory;
    this.objectWrapperFactory = objectWrapperFactory;
    this.reflectorFactory = reflectorFactory;

    if (object instanceof ObjectWrapper) {
      this.objectWrapper = (ObjectWrapper) object;
    } else if (objectWrapperFactory.hasWrapperFor(object)) {
      this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
    } else if (object instanceof Map) {
      this.objectWrapper = new MapWrapper(this, (Map) object);
    } else if (object instanceof Collection) {
      this.objectWrapper = new CollectionWrapper(this, (Collection) object);
    } else {
      // 首次进入执行BeanWapper
      this.objectWrapper = new BeanWrapper(this, object);
    }
  }

  public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    if (object == null) {
      return SystemMetaObject.NULL_META_OBJECT;
    } else {
      return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    }
  }

  public ObjectFactory getObjectFactory() {
    return objectFactory;
  }

  public ObjectWrapperFactory getObjectWrapperFactory() {
    return objectWrapperFactory;
  }

  public ReflectorFactory getReflectorFactory() {
	return reflectorFactory;
  }

  public Object getOriginalObject() {
    return originalObject;
  }

  public String findProperty(String propName, boolean useCamelCaseMapping) {
    return objectWrapper.findProperty(propName, useCamelCaseMapping);
  }

  public String[] getGetterNames() {
    return objectWrapper.getGetterNames();
  }

  public String[] getSetterNames() {
    return objectWrapper.getSetterNames();
  }

  public Class<?> getSetterType(String name) {
    return objectWrapper.getSetterType(name);
  }

  public Class<?> getGetterType(String name) {
    return objectWrapper.getGetterType(name);
  }

  public boolean hasSetter(String name) {
    return objectWrapper.hasSetter(name);
  }

  public boolean hasGetter(String name) {
    return objectWrapper.hasGetter(name);
  }

  public Object getValue(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return null;
      } else {
        return metaValue.getValue(prop.getChildren());
      }
    } else {
      return objectWrapper.get(prop);
    }
  }

  public void setValue(String name, Object value) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        if (value == null && prop.getChildren() != null) {
          // don't instantiate child path if value is null
          return;
        } else {
          metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
        }
      }
      metaValue.setValue(prop.getChildren(), value);
    } else {
      objectWrapper.set(prop, value);
    }
  }

  public MetaObject metaObjectForProperty(String name) {
    Object value = getValue(name);
    return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
  }

  public ObjectWrapper getObjectWrapper() {
    return objectWrapper;
  }

  public boolean isCollection() {
    return objectWrapper.isCollection();
  }

  public void add(Object element) {
    objectWrapper.add(element);
  }

  public <E> void addAll(List<E> list) {
    objectWrapper.addAll(list);
  }

}



BeanWrapper://TODO
ublic class BeanWrapper extends BaseWrapper {

  private final Object object;
  private final MetaClass metaClass;

  public BeanWrapper(MetaObject metaObject, Object object) {
    super(metaObject);
    this.object = object;
    this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
  }

  @Override
  public Object get(PropertyTokenizer prop) {
    if (prop.getIndex() != null) {
      Object collection = resolveCollection(prop, object);
      return getCollectionValue(prop, collection);
    } else {
      return getBeanProperty(prop, object);
    }
  }

  @Override
  public void set(PropertyTokenizer prop, Object value) {
    if (prop.getIndex() != null) {
      Object collection = resolveCollection(prop, object);
      setCollectionValue(prop, collection, value);
    } else {
      setBeanProperty(prop, object, value);
    }
  }

  @Override
  public String findProperty(String name, boolean useCamelCaseMapping) {
    return metaClass.findProperty(name, useCamelCaseMapping);
  }

  @Override
  public String[] getGetterNames() {
    return metaClass.getGetterNames();
  }

  @Override
  public String[] getSetterNames() {
    return metaClass.getSetterNames();
  }

  @Override
  public Class<?> getSetterType(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return metaClass.getSetterType(name);
      } else {
        return metaValue.getSetterType(prop.getChildren());
      }
    } else {
      return metaClass.getSetterType(name);
    }
  }

  @Override
  public Class<?> getGetterType(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return metaClass.getGetterType(name);
      } else {
        return metaValue.getGetterType(prop.getChildren());
      }
    } else {
      return metaClass.getGetterType(name);
    }
  }

  @Override
  public boolean hasSetter(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      if (metaClass.hasSetter(prop.getIndexedName())) {
        MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
        if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
          return metaClass.hasSetter(name);
        } else {
          return metaValue.hasSetter(prop.getChildren());
        }
      } else {
        return false;
      }
    } else {
      return metaClass.hasSetter(name);
    }
  }

  @Override
  public boolean hasGetter(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      if (metaClass.hasGetter(prop.getIndexedName())) {
        MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
        if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
          return metaClass.hasGetter(name);
        } else {
          return metaValue.hasGetter(prop.getChildren());
        }
      } else {
        return false;
      }
    } else {
      return metaClass.hasGetter(name);
    }
  }

  @Override
  public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
    MetaObject metaValue;
    Class<?> type = getSetterType(prop.getName());
    try {
      Object newObject = objectFactory.create(type);
      metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory());
      set(prop, newObject);
    } catch (Exception e) {
      throw new ReflectionException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e);
    }
    return metaValue;
  }

  private Object getBeanProperty(PropertyTokenizer prop, Object object) {
    try {
      Invoker method = metaClass.getGetInvoker(prop.getName());
      try {
        return method.invoke(object, NO_ARGUMENTS);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    } catch (RuntimeException e) {
      throw e;
    } catch (Throwable t) {
      throw new ReflectionException("Could not get property '" + prop.getName() + "' from " + object.getClass() + ".  Cause: " + t.toString(), t);
    }
  }

  private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
    try {
      Invoker method = metaClass.getSetInvoker(prop.getName());
      Object[] params = {value};
      try {
        method.invoke(object, params);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    } catch (Throwable t) {
      throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);
    }
  }

  @Override
  public boolean isCollection() {
    return false;
  }

  @Override
  public void add(Object element) {
    throw new UnsupportedOperationException();
  }

  @Override
  public <E> void addAll(List<E> list) {
    throw new UnsupportedOperationException();
  }

}



MetaClass:参考启动流程2

BaseWrapper://TODO
public abstract class BaseWrapper implements ObjectWrapper {

  protected static final Object[] NO_ARGUMENTS = new Object[0];
  protected final MetaObject metaObject;

  protected BaseWrapper(MetaObject metaObject) {
    this.metaObject = metaObject;
  }

  protected Object resolveCollection(PropertyTokenizer prop, Object object) {
    if ("".equals(prop.getName())) {
      return object;
    } else {
      return metaObject.getValue(prop.getName());
    }
  }

  protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
    if (collection instanceof Map) {
      return ((Map) collection).get(prop.getIndex());
    } else {
      int i = Integer.parseInt(prop.getIndex());
      if (collection instanceof List) {
        return ((List) collection).get(i);
      } else if (collection instanceof Object[]) {
        return ((Object[]) collection)[i];
      } else if (collection instanceof char[]) {
        return ((char[]) collection)[i];
      } else if (collection instanceof boolean[]) {
        return ((boolean[]) collection)[i];
      } else if (collection instanceof byte[]) {
        return ((byte[]) collection)[i];
      } else if (collection instanceof double[]) {
        return ((double[]) collection)[i];
      } else if (collection instanceof float[]) {
        return ((float[]) collection)[i];
      } else if (collection instanceof int[]) {
        return ((int[]) collection)[i];
      } else if (collection instanceof long[]) {
        return ((long[]) collection)[i];
      } else if (collection instanceof short[]) {
        return ((short[]) collection)[i];
      } else {
        throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
      }
    }
  }

  protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {
    if (collection instanceof Map) {
      ((Map) collection).put(prop.getIndex(), value);
    } else {
      int i = Integer.parseInt(prop.getIndex());
      if (collection instanceof List) {
        ((List) collection).set(i, value);
      } else if (collection instanceof Object[]) {
        ((Object[]) collection)[i] = value;
      } else if (collection instanceof char[]) {
        ((char[]) collection)[i] = (Character) value;
      } else if (collection instanceof boolean[]) {
        ((boolean[]) collection)[i] = (Boolean) value;
      } else if (collection instanceof byte[]) {
        ((byte[]) collection)[i] = (Byte) value;
      } else if (collection instanceof double[]) {
        ((double[]) collection)[i] = (Double) value;
      } else if (collection instanceof float[]) {
        ((float[]) collection)[i] = (Float) value;
      } else if (collection instanceof int[]) {
        ((int[]) collection)[i] = (Integer) value;
      } else if (collection instanceof long[]) {
        ((long[]) collection)[i] = (Long) value;
      } else if (collection instanceof short[]) {
        ((short[]) collection)[i] = (Short) value;
      } else {
        throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
      }
    }
  }

}

分析一下调用链:
1.Configuration传入:
object, objectFactory, objectWrapperFactory, reflectorFactory
object为参数对象ObjectFactory即对象工厂,通过反射创建对象,
objectWrapperFactory是DefaultObjectWrapperFactory,其为空实现,实现了ObjectWrapperFactory,先不说明有什么作用,
reflectorFactory则非常重要,包含了Reflector的缓存,Reflector则是封装了一个类型的getter setter和相应实现了InvokcationHandler接口的Invoker,用来设置相应的属性值。
2。MetaObject 构造相应的Wrapper实现,构造几种BeanWrapper时都传入了this即MetaObject,MetaObject有两个作用:供抽象父类BaseWrapper调用MetaObject方法和获取MetaObject的reflectorFactory,通过reflectorFactory可以构造MetaClass,MetaClass则是Relector的封装。查看BeanWrapper的get方法调用了getBeanProperty而这个方法继续调用了metaClass.getGetInvoker即reflector的getGetInvoker。而MetaObject的getValue方法则调用了objectWrapper的get方法。
public Object getValue(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return null;
      } else {
        return metaValue.getValue(prop.getChildren());
      }
    } else {
      return objectWrapper.get(prop);
    }
  }

总结一下:为什么要将一个简单的Invoker对象封装如此多层呢?有什么具体的作用呢?
只要通过MetaOject的getValue方法就可以将任何对象封装成像一个Map医院使用。

DynamicContext的作用:DynamicContext 包含实例变量ContextMap和sqlBuilder,ContextMap中有传入如parameterObject和DatabaseId。还有什么用?//TODO

继续执行DynamicSqlSource#getBoundSql
这里的rootSqlNode是解析流程(3)中的MixedSqlNode的实例,MixedSqlNode中contents存储了所有解析后的动态和静态的SqlNode的实现。所有MixedSqlNode的apply方法仅仅是执行contents中的SqlNode的apply方法,apply方法只有一个入参DynamicContext
    rootSqlNode.apply(context);

如果sqlNode是StaticTextSqlNode,调用 context.appendSql(text);将静态sql文本加在context的sqlBuilder尾部
public class MixedSqlNode implements SqlNode {
  private final List<SqlNode> contents;

  public MixedSqlNode(List<SqlNode> contents) {
    this.contents = contents;
  }

  @Override
  public boolean apply(DynamicContext context) {
   //最终都会执行StaticTextSqlNode的apply方法,将sql拼接在Dynamic中的sqlBuilder中
    for (SqlNode sqlNode : contents) {
      sqlNode.apply(context);
    }
    return true;
  }
}


如果是IfSqlNode调用Ogln解析器解析使用binds赋值的test表达式成功则添加否则不添加。

public class IfSqlNode implements SqlNode {
  private final ExpressionEvaluator evaluator;
  private final String test;
  //IfSqlNode也包含contents,可能是MixedSqlNode,StaticTextSqlNode
  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) {
    //判断test表达式值,这里通过DynamicContext.ContextAccessor的getProperty方法调用ContextMap中的get方法继而调用MetaObject的getValue最终获取到传入对象的属性值。
    if (evaluator.evaluateBoolean(test, context.getBindings())) {
      contents.apply(context);
      return true;
    }
    return false;
  }


继续执行   
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());


执行到这里可以发现SqlNode的主要作用就动态的拼接sql语句,产出sql语句,而DynamicContext的作用就是产出sql(待#{}表达式)和将入参封装为Map(contextMap)对象。

SqlSourceBuilder和内部类都继承了BaseBuilder表明自己是个解析器并且获得了 typeAliasRegistry、typeHandlerRegistry两个属性 和一些基本的方法。

  protected final TypeHandlerRegistry typeHandlerRegistry;
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和GenericTokenParser解析 originalSql并将originalSql中的#{}替换为?
    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;
      //这里在进行newMetaObject的时候additionalParameters已经是一个ContextMap对象
      //所以返回的metaParameters中的ObjectWrapper是一个不择不扣的MapWapper
     //也就是说最后任何对象都会被转换成一个MappWapper
      this.metaParameters = configuration.newMetaObject(additionalParameters);
    }

    public List<ParameterMapping> getParameterMappings() {
      return parameterMappings;
    }

    @Override
    public String handleToken(String content) {
      //生成ParameterMapping
      parameterMappings.add(buildParameterMapping(content));
      return "?";
    }

    private ParameterMapping buildParameterMapping(String content) {
    //ParameterExpression.parse方法会解析content中是否还有其他表达式,
   //最终生成 propertiesMap property->#{}中包含的值 如 property->id
  //和其他表达式或者jdbc和ojdbc之间的映射
      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 || Map.class.isAssignableFrom(parameterType)) {
        propertyType = Object.class;
      } else {
       //这里通过寻找参数类型中是否有对应的属性,有则propertyType被设置为相应的类型
        MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());
        if (metaClass.hasGetter(property)) {
          propertyType = metaClass.getGetterType(property);
        } else {
          propertyType = Object.class;
        }
      }
      ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
      Class<?> javaType = propertyType;
      String typeHandlerAlias = null;
      //检查是否有Java类型和jdbc类型的映射
      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) {
       //有则为parameterMapping设置相应的类型处理器
        builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
      }
    //构建ParameterMapping
      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);
      }
    }
  }

}



ParameterMapping://TODO


继续执行SqlSourceBuilder#parse,生成StaticSqlSource,

new StaticSqlSource(configuration, sql, handler.getParameterMappings());

public class StaticSqlSource implements SqlSource {

  private final String sql;
  private final List<ParameterMapping> parameterMappings;
  private final Configuration configuration;

  public StaticSqlSource(Configuration configuration, String sql) {
    this(configuration, sql, null);
  }

  public StaticSqlSource(Configuration configuration, String sql, List<ParameterMapping> parameterMappings) {
    this.sql = sql;
    this.parameterMappings = parameterMappings;
    this.configuration = configuration;
  }

  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    return new BoundSql(configuration, sql, parameterMappings, parameterObject);
  }

}

BoundSql:
public class BoundSql {

  private final String sql;
  private final List<ParameterMapping> parameterMappings;
  private final Object parameterObject;
  private final Map<String, Object> additionalParameters;
  private final MetaObject metaParameters;

  public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) {
    this.sql = sql;
    this.parameterMappings = parameterMappings;
    this.parameterObject = parameterObject;
    this.additionalParameters = new HashMap<String, Object>();
    this.metaParameters = configuration.newMetaObject(additionalParameters);
  }

  public String getSql() {
    return sql;
  }

  public List<ParameterMapping> getParameterMappings() {
    return parameterMappings;
  }

  public Object getParameterObject() {
    return parameterObject;
  }

  public boolean hasAdditionalParameter(String name) {
    String paramName = new PropertyTokenizer(name).getName();
    return additionalParameters.containsKey(paramName);
  }

  public void setAdditionalParameter(String name, Object value) {
    metaParameters.setValue(name, value);
  }

  public Object getAdditionalParameter(String name) {
    return metaParameters.getValue(name);
  }
}


观察BoundSql和StaticSqlSource,发现BoundSql只比StaticSqlSource多了metaParameters的参数。
执行到这里不妨总结一下Sql解析的流程和使用到的几个核心类、接口:
在mapper解析阶段XMLScriptBuilder#parseDynamicTags生成MixedSqlNode和
parseScriptNode生成DynamicSqlSource组装生成MappedStatement,执行时传入参数并执行DynamicSqlSource中rootSqlNode最终生成静态的StaticSqlSource,静态的StaticSqlSource是已经解析成jdbc驱动可以执行的语句,进一步加上入参对象封装而成的MetaObject成了BoundSql。

SqlNode接口:表示每个sql片段,有两种实现类,动态:的有if where 等和静态的sql片段,表示不含表达式的sql语句。此接口只包含一个方法,此方法入参为DynamicContext,每次调用判断将sql追加到上下文的末尾,形成整个一个语句。各种SqlNode在XMLScriptBuilder#parseDynamicTags被创建加入一个MixedSqlNode中,MapperStatement的rootSqlNode执行apply后销亡。
ParameterMapping:包含当前#{}中包含的参数对象类型的属性名称、类型等,执行阶段被ParameterMappingTokenHandler#buildParameterMapping或者MapperBuilderAssistant#buildParameterMapping生成,并加入SqlSource
SqlSource:在动态的SqlSource包含SqlNode的实例,静态SqlSource包含解析后的sql和参数映射ParameterMapping,DynamicSqlSource在解析阶段使用,StaticSqlSource在执行阶段使用。

BoundSql:包含静态sql语句,ParameterMapping参数映射,parameterObject原生传入参数,additionalParameters额外的参数( DynamicContext中所有的值)以及metaParameters,额外参数对应的获取方法,BoundSql包含了一个sql得以执行的所有必需条件。

继续执行MapperStatement#getBoundSql
到此MapperStatement的getBoundSql就执行完成了

分享到:
评论

相关推荐

    mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip

    mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip ...

    mybatis-generator-config_1_0.dtd

    mybatis-generator-config_1_0.dtd文件存在于mybatis-generator-core-1.3.2.jar包中,路径如下org/mybatis/generator/config/xml/mybatis-generator-config_1_0.dtd 可以设置开发工具的dtd配置,配置...

    MyBatis-Plus 的官方示例(mybatis-plus-samples-master.zip)

    mybatis-plus-sample-generator: 代码生成器示例 mybatis-plus-sample-crud: 完整 CRUD 示例 mybatis-plus-sample-wrapper: 条件构造器示例 mybatis-plus-sample-pagination: 分页功能示例 mybatis-plus-sample-...

    mybatis-3-config.dtd mybatis-3-mapper.dtd

    在MyBatis中,`mybatis-3-config.dtd` 和 `mybatis-3-mapper.dtd` 是两个至关重要的DTD(Document Type Definition)文件,它们定义了MyBatis配置文件和映射文件的结构和规则。 首先,让我们深入了解一下`mybatis-3...

    mybatis-generator-1.3.2 代码生成

    【标题】"mybatis-generator-1.3.2 代码生成" 涉及到的是一个基于MyBatis框架的代码生成工具,主要用于自动化地创建MyBatis的SQL映射文件、Mapper接口、Mapper XML文件以及实体类。这个工具极大地提高了开发效率,...

    mybatis-3-config/mapper.dtd 解决mybatis头文件报错

    然后打开eclipse -&gt;Window-&gt;prefenrence-&gt;XML-&gt;XML Catalog-&gt;User Specifiled Entreis-&gt;Add-&gt;Location(此处是你放dtd文件的位置例如:‪D:\mybatis\mybatis-3-config.dtd)-&gt;Key(如果更改config,此处应该是:-//...

    mybatis-generator-core-1.4.0-bundle.zip

    总的来说,`mybatis-generator-core-1.4.0-bundle.zip` 是一个方便的工具,可以帮助开发者快速生成与数据库交互的 MyBatis 代码,简化开发流程,提高代码质量。在实际开发中,结合合适的配置和定制模板,可以进一步...

    mybatis-generator-gui

    总的来说,mybatis-generator-gui是一个便捷的开发工具,通过图形界面简化了MyBatis的Mapper文件生成过程,提高了开发效率,同时提供了数据库类的自动生成功能,使开发者能更专注于业务逻辑的实现。对于使用MyBatis...

    mybatis-plus-generator-3.0.6.jar

    mybatis-plus-generato.jar 包,各个版本,免费下载。 mybatis-plus 代码生成器生成代码框架。各个版本,免费下载。 下载不了,关注我,评论区联系我。

    mybatis-generator-core-1.3.6代码自动生成器官方最新版本

    使用命令行直接执行,java -jar mybatis-generator-core-1.3.6.jar -configfile generatorConfig.xml -overwrite 包含mybatis-generator-core-1.3.6.zip代码自动生成器官方最新版本的jar包、mysql数据库连接jar包、...

    mybatis-plus-generator-3.4.0.jar

    mybatis-plus-generato.jar 包,各个版本,免费下载。 mybatis-plus 代码生成器生成代码框架。各个版本,免费下载。 下载不了,关注我,评论区联系我。

    mybatis-generator-core自动生成实体类、dao接口和mapping映射文件

    利用mybatis-generator-core可以自动生成实体类、dao接口和mapping映射文件,里头也提供了使用说明: 1、进入lib文件夹里头。 2、修改generatorConfig.xml配置 主要修改数据库地址,用户名,密码,以及数据库名称,...

    mybatis-generator-core-1.3.2注释修改

    1. **下载源码**:首先,你需要下载`mybatis-generator-core-1.3.2`的源代码,这通常可以从MyBatis的官方网站或者GitHub仓库获取。 2. **理解源码结构**:MBG的核心在于`org.mybatis.generator.api`包,其中`...

    mybatis-plus-generator-maven-plugin-1.0.0.jar

    为了在项目中快捷方便的代码生成,将mybatis-plus-generator封装为了一个maven的插件`mybatis-plus-generator-maven-plugin。使用文档参考:https://blog.csdn.net/xiweiller/article/details/103072165

    mybatis-generator-gui-0.8.8-SNAPSHOT.jar

    mybatis-generator-gui自动生成代码的工具,但是jdk必须大于1.8

    mybatis-generator-core-1.3.2 自动生成文件

    8. **Maven集成**:在大型项目中,通常会将MyBatis Generator集成到Maven或Gradle构建系统中,通过执行特定的目标或任务来自动化代码生成,确保每次构建时都能得到最新的代码。 9. **性能优化**:虽然MyBatis ...

    mybatis-generator-gui-plus

    总之,`mybatis-generator-gui-plus`是提升MyBatis开发效率的重要工具,它通过图形化的操作界面简化了代码生成流程,降低了开发难度,让开发者能够更专注于业务逻辑的实现,从而提高整体项目的开发质量和速度。...

    mybatis-generator-core-1.3.2

    1. `mybatis-generator-core-1.3.2.jar`:MBG 的核心库,包含所有实现代码生成功能的类和接口。 2. `lib` 目录:可能包含 MBG 运行时依赖的第三方库,如 JDBC 驱动等。 3. `README` 或 `doc` 文件:提供关于如何使用...

    mybatis-spring-1.3.1.jar下载

    下面将详细介绍MyBatis-Spring的主要功能、工作原理以及如何与MyBatis-3.4.4等版本配合使用。 MyBatis-Spring的主要功能: 1. **自动扫描与配置**:MyBatis-Spring能够自动扫描项目中的Mapper接口,并根据这些接口...

    mybatis-spring-2.0.6.jar

    mybatis-spring-2.0.6.jar

Global site tag (gtag.js) - Google Analytics