Mybatis 之 构造Mapper (MapperProxy)

来源:互联网 发布:北京sql培训 编辑:程序博客网 时间:2024/05/18 03:50

我们在代码中使用:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

查看DefaultSqlSession的getMapper方法:

  @Override  public <T> T getMapper(Class<T> type) {    return configuration.<T>getMapper(type, this);  }


接着再看Configuration的getMapper方法:

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {    return mapperRegistry.getMapper(type, sqlSession);  }

看来还是一个MapperRegistry的对象在处理Mapper:

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

从代码中我们看到试图从一个叫knownMappers的变量取出MapperProxyFactory。

我们看看这个knownMapper在MapperRegistry中的定义:

private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();

有getMapper方法,那么必然后addMapper方法:

  public <T> void addMapper(Class<T> type) {    if (type.isInterface()) {      if (hasMapper(type)) {        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");      }      boolean loadCompleted = false;      try {        knownMappers.put(type, new MapperProxyFactory<T>(type));        // It's important that the type is added before the parser is run        // otherwise the binding may automatically be attempted by the        // mapper parser. If the type is already known, it won't try.        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);        parser.parse();        loadCompleted = true;      } finally {        if (!loadCompleted) {          knownMappers.remove(type);        }      }    }  }

我们在回过头来看getMapper是如何获得Mapper对象的:

1.先获取MapperProxyFactory

2.再调用MapperProxyFactory对象的newInstance方法获得Mapper。


我们看MapperProxyFactory代码:

  public T newInstance(SqlSession sqlSession) {    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);    return newInstance(mapperProxy);  }  protected T newInstance(MapperProxy<T> mapperProxy) {    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);  }

这里就是返回的一个代理类实例MapperProxy。

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);  }  private MapperMethod cachedMapperMethod(Method method) {    MapperMethod mapperMethod = methodCache.get(method);    if (mapperMethod == null) {      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());      methodCache.put(method, mapperMethod);    }    return mapperMethod;  }  @UsesJava7  private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)      throws Throwable {    final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class        .getDeclaredConstructor(Class.class, int.class);    if (!constructor.isAccessible()) {      constructor.setAccessible(true);    }    final Class<?> declaringClass = method.getDeclaringClass();    return constructor        .newInstance(declaringClass,            MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED                | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)        .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);  }  /**   * Backport of java.lang.reflect.Method#isDefault()   */  private boolean isDefaultMethod(Method method) {    return ((method.getModifiers()        & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC)        && method.getDeclaringClass().isInterface();  }}

要使用Java的动态代理就必须得实现InvocationHandler接口:

  @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);  }

首先判断代理对象是一个接口还是一个类,显然我们没有对mapper接口进行任何实现,那么它将执行

final MapperMethod mapperMethod = cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args);

生成一个MapperMethod对象,接着调用其execute方法,把sqlSession和参数传递进去,执行Mapper方法。






原创粉丝点击