2018-03-29 MyBatis Mapper原理浅析

思考问题:Mapper是定义的接口,如何完成代码实现的?

其实在业务代码使用的Mapper并不是自己所建立的Mapper接口,而是通过MyBatis的
MapperProxyFactory.newInstance(sqlSession);动态代理生成的MapperProxy的代理对象。

/**
* 映射器代理工厂
*/
public class MapperProxyFactory {

 private final Class mapperInterface;
 private Map methodCache = new ConcurrentHashMap();

 public MapperProxyFactory(Class mapperInterface) {
   this.mapperInterface = mapperInterface;
 }

 public Class getMapperInterface() {
   return mapperInterface;
 }

 public Map getMethodCache() {
   return methodCache;
 }

 @SuppressWarnings("unchecked")
 protected T newInstance(MapperProxy mapperProxy) {
   //用JDK自带的动态代理生成映射器
   return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
 }

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

}
思考问题:MapperProxy代理对象又是什么呢?

想了解MapperProxy,需要先了解Java的动态代理技术。
MapperProxy通过重写invoke方法,完成Mapper接口的示例化。

/**
 * 映射器代理,代理模式
 *
 */
public class MapperProxy implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class mapperInterface;
  private final Map methodCache;

  public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //代理以后,所有Mapper的方法调用时,都会调用这个invoke方法
    //并不是任何一个方法都需要执行调用代理对象进行执行,如果这个方法是Object中通用的方法(toString、hashCode等)无需执行
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    //这里优化了,去缓存中找MapperMethod
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //执行
    return mapperMethod.execute(sqlSession, args);
  }

  //去缓存中找MapperMethod
  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      //找不到才去new
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

}

你可能感兴趣的:(2018-03-29 MyBatis Mapper原理浅析)