为什么Mapper接口不需要实现类?

四个字回答:动态代理,我们来看一下获取Mapper的过程:

  • 获取Mapper

我们都知道定义的Mapper接口是没有实现类的,Mapper映射其实是通过动态代理实现的。

BlogMapper mapper = session.getMapper(BlogMapper.class);

七拐八绕地进去看一下,发现获取Mapper的过程,需要先获取MapperProxyFactory——Mapper代理工厂。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    } else {
        try {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception var5) {
            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}
  • MapperProxyFactory

MapperProxyFactory的作用是生成MapperProxy(Mapper代理对象)。

public class MapperProxyFactory<T> {
  private final Class<T> mapperInterface;
  ……
  protected T newInstance(MapperProxy<T> mapperProxy) {
      return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
      MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
      return this.newInstance(mapperProxy);
  }
}

这里可以看到动态代理对接口的绑定,它的作用就是生成动态代理对象(占位),而代理的方法被放到了MapperProxy中。

  • MapperProxy

MapperProxy里,通常会生成一个MapperMethod对象,它是通过cachedMapperMethod方法对其进行初始化的,然后执行excute方法。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
    } catch (Throwable var5) {
        throw ExceptionUtil.unwrapThrowable(var5);
    }
}
  • MapperMethod

MapperMethod里的excute方法,会真正去执行sql。这里用到了命令模式,其实绕一圈,最终它还是通过SqlSession的实例去运行对象的sql。

public Object execute(SqlSession sqlSession, Object[] args) {
      Object result;
      Object param;
      ……
      case SELECT:
          if (this.method.returnsVoid() && this.method.hasResultHandler()) {
              this.executeWithResultHandler(sqlSession, args);
              result = null;
          } else if (this.method.returnsMany()) {
              result = this.executeForMany(sqlSession, args);
          } else if (this.method.returnsMap()) {
              result = this.executeForMap(sqlSession, args);
          } else if (this.method.returnsCursor()) {
              result = this.executeForCursor(sqlSession, args);
          } else {
              param = this.method.convertArgsToSqlCommandParam(args);
              result = sqlSession.selectOne(this.command.getName(), param);
              if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
                  result = Optional.ofNullable(result);
              }
          }
          break;
         ……
  }

标签: java, Java面试题, mybatis, Java问题合集, Java编程, Java问题精选, Java常见问题, MyBatis面试题