Mybatis之Mapper

mybatis中mapper都是接口,我們在使用的時候都是可以通過@Autowired依賴注入進mapper實例。這些mapper實例都是由MapperProxyFactory工廠生成的MapperProxy代理對象,這里主要涉及到了Mapper、MapperProxy和MapperProxyFactory三個對象,以下是對這些對象的簡要描述:

  • Mapper:這個是我們定義的Mapper接口,在應用中使用。
  • MapperProxy:這個是使用JDK動態代理對Mapper接口生成的代理實例,也就是我們實際使用引入的實例對象
  • MapperProxyFactory:這個是使用了工廠模式,用來對某一mapper接口來生成MapperProxy實例的。

以下來對上述接口和類來進行源碼分析:

MapperProxyFactory源碼:

public class MapperProxyFactory<T> {
  //mapper接口,就是實際我們定義的接口,也是需要代理的target
  private final Class<T> mapperInterface;
  //Method的緩存,應該是當前Mapper里面的所有method,這里有點疑問
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();

  //給對應的mapper接口生成MapperProxy代理對象
  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

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

MapperProxy源碼:

public class MapperProxy<T> implements InvocationHandler, Serializable {
  //當前會話
  private final SqlSession sqlSession;
  //target對象,mapper接口
  private final Class<T> mapperInterface;
  //方法緩存,key是Mapper接口里面的Method對象
  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 {
      //判斷方法是否為Obect里面聲明的對象
      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);
    }
    //創建并緩存MapperMethod
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //執行method方法
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
  //如果緩存里面沒有的話就創建并且放入緩存中,這里緩存是一個ConcurrentHashMap
    return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
  }
}

這里的MapperProxy是對Mapper接口的代理對象,當調用mapper接口的方法時會進行攔截,生成MapperMethod對象并放入緩存中,這里的緩存存在的意義就是不用下次再來生成該接口方法的MapperMethod對象,然后執行對應的方法。這里根據方法類型(insert | update)來路由執行對應的方法。

Mapper接口內的方法不能重載

原因:在Mapper接口生成的代理MapperProxy中,可以看到在方法被攔截的處理動作中,是把方法對應的MapperMethod放到了緩存中,緩存是以Method對象作為key,所以是不允許重載這種情況的。

final MapperMethod mapperMethod = cachedMapperMethod(method);
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容