Mybatis的源码解析(三):获得xxxMapper对象并执行

框架

在这里插入图片描述

3.获得xxxMapper对象并执行

  • 总体的过程
    在这里插入图片描述
  • 接下来我们就来执行自己写的增删改查的方法
//得到SqlSessionFactory
SqlSessionFactory sessionFactory=
                new SqlSessionFactoryBuilder().build(reader);
//使用SqlSessionFactory拿到SqlSession
SqlSession session = sessionFactory.openSession();
//生成动态代理对象
StudentMapper studentMapper = session.getMapper(StudentMapper.class);
//在此处打断点,Debug我们自己的方法
Student student = studentMapper.queryStudentByStuno(1);
  • 结果我们进入到了Mapper的动态代理类,这个类实现了InvocationHandler,这个就是Mapper的动态代理对象
public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    //缓存操作
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
  • 我们再看一下InvocationHandler JDK动态代理接口,在我们实现增删改查时,并不是我们定义的方法来执行,而是交给代理类MapperProxy来执行的
package java.lang.reflect;

/**
 * {@code InvocationHandler} is the interface implemented by
 * the <i>invocation handler</i> of a proxy instance.
 *
 * <p>Each proxy instance has an associated invocation handler.
 * When a method is invoked on a proxy instance, the method
 * invocation is encoded and dispatched to the {@code invoke}
 * method of its invocation handler.
 *
 * @author      Peter Jones
 * @see         Proxy
 * @since       1.3
 */
public interface InvocationHandler {

    /**
     * Processes a method invocation on a proxy instance and returns
     * the result.  This method will be invoked on an invocation handler
     * when a method is invoked on a proxy instance that it is
     * associated with.
     *
     * @param   proxy the proxy instance that the method was invoked on
     *
     * @param   method the {@code Method} instance corresponding to
     * the interface method invoked on the proxy instance.  The declaring
     * class of the {@code Method} object will be the interface that
     * the method was declared in, which may be a superinterface of the
     * proxy interface that the proxy class inherits the method through.
     *
     * @param   args an array of objects containing the values of the
     * arguments passed in the method invocation on the proxy instance,
     * or {@code null} if interface method takes no arguments.
     * Arguments of primitive types are wrapped in instances of the
     * appropriate primitive wrapper class, such as
     * {@code java.lang.Integer} or {@code java.lang.Boolean}.
     *
     * @return  the value to return from the method invocation on the
     * proxy instance.  If the declared return type of the interface
     * method is a primitive type, then the value returned by
     * this method must be an instance of the corresponding primitive
     * wrapper class; otherwise, it must be a type assignable to the
     * declared return type.  If the value returned by this method is
     * {@code null} and the interface method's return type is
     * primitive, then a {@code NullPointerException} will be
     * thrown by the method invocation on the proxy instance.  If the
     * value returned by this method is otherwise not compatible with
     * the interface method's declared return type as described above,
     * a {@code ClassCastException} will be thrown by the method
     * invocation on the proxy instance.
     *
     * @throws  Throwable the exception to throw from the method
     * invocation on the proxy instance.  The exception's type must be
     * assignable either to any of the exception types declared in the
     * {@code throws} clause of the interface method or to the
     * unchecked exception types {@code java.lang.RuntimeException}
     * or {@code java.lang.Error}.  If a checked exception is
     * thrown by this method that is not assignable to any of the
     * exception types declared in the {@code throws} clause of
     * the interface method, then an
     * {@link UndeclaredThrowableException} containing the
     * exception that was thrown by this method will be thrown by the
     * method invocation on the proxy instance.
     *
     * @see     UndeclaredThrowableException
     */
     //动态代理接口的invoke(执行方法)
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
  • mapperMethod执行DefaultSqlSession,里面有Configuration和Executor,args指的是参数
@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    
    return mapperMethod.execute(sqlSession, args);
  }
  • 然后进入到execute这个方法中
 public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //通过command.geteType()来判断当前进行的是什么操作,例如select ,update,delete等等
    switch (command.getType()) {
      case INSERT: {
      Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

在这里插入图片描述

case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          //处理增删改查参数的方法
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
  • 进入到 Object param = method.convertArgsToSqlCommandParam(args);方法中
 public Object getNamedParams(Object[] args) {
    final int paramCount = names.size();
    //如果参数为0个,则返回null
    if (args == null || paramCount == 0) {
      return null;
      //如果参数为1个,则返回第一个值 
    } else if (!hasParamAnnotation && paramCount == 1) {
      return args[names.firstKey()];
    } else {
      //如果参数是多个,则放到一个Map集合中
      final Map<String, Object> param = new ParamMap<Object>();
      int i = 0;
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
      	//取出对应的键K,值
        param.put(entry.getValue(), args[entry.getKey()]);
        // add generic param names (param1, param2, ...)
        final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
        // ensure not to overwrite parameter named with @Param
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
    }
  }
  • 我输入的参数为1个,就执行一个参数的,然后返回的是我要查询的1
    在这里插入图片描述
  • 处理完参数之后就可以真正的查询了
result = sqlSession.selectOne(command.getName(), param);
  • selectOne里面使用的是selectList方法来查询
@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, RowBounds rowBounds) {
   try {
     //使用configuration.getMappedStatement拿到所有的增删改查的对象
     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();
   }
 }
  • 进入到query方法中
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
@Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
 }

asdfsdf

  • 执行SQL是Executor
  • private final Executor delegate;
    在这里插入图片描述
  • Mybatis执行流程总结
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
  • 原理总结
  1. 根据 配置文件(全局、sql映射)初始化Configuration对象
  2. 创建一个DefaultSqlSession对象,
    他里面包含Configuration以及
    Executor(根据全局配置文件中的defaultExecutorType创建对应的Executor)
  3. DefaultSqlSession.getMapper(),拿到Mapper接口对应的MapperProxy.
  4. MapperProxy里面有(DefaultSqlSession);
  5. 执行增删改查方法:
    • 调用 DefaultSqlSession的增删改查(Executor);
    • 会创建一个StatementHandler对象。(同时也会创建ParameterHandler和ResultSethandler)
    • 调用StatementHandler预编译参数以及设置参数值,使用ParameterHandler
    • 调用StatementHandler的增删改查方法;
    • ResultSethandler封装结果;
  • 注意:
    四大对象每个创建的时候都有:
    interceptorChain.pluginall(parameterHandler);
    
发布了47 篇原创文章 · 获赞 34 · 访问量 8872

猜你喜欢

转载自blog.csdn.net/weixin_42893085/article/details/105183616