MyBatis架構中Mapper映射配置的使用及原理解析(七) MapperProxy,MapperProxyFactory

來源:互聯網
上載者:User

標籤:div   factory   actor   rgs   獲得   hashmap   new   iba   current   

從上文<MyBatis架構中Mapper映射配置的使用及原理解析(六) MapperRegistry> 中我們知道DefaultSqlSession的getMapper方法,最後是通過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);        }      }    }  }  

 在<MyBatis架構中Mapper映射配置的使用及原理解析(四) 解析Mapper介面映射xml檔案> 文章中,解析玩xml後,綁定命名空間bindMapperForNamespace()方法

//綁定到命名空間private void bindMapperForNamespace() {  String namespace = builderAssistant.getCurrentNamespace();  if (namespace != null) {    Class<?> boundType = null;    try {      boundType = Resources.classForName(namespace);    } catch (ClassNotFoundException e) {      //ignore, bound type is not required    }    if (boundType != null) {      if (!configuration.hasMapper(boundType)) {        // Spring may not know the real resource name so we set a flag        // to prevent loading again this resource from the mapper interface        // look at MapperAnnotationBuilder#loadXmlResource        configuration.addLoadedResource("namespace:" + namespace);        configuration.addMapper(boundType);      }    }  }}

我們看到 

configuration.addMapper(boundType);

正是調用MapperRegistry.addMapper方法

  public <T> void addMapper(Class<T> type) {    mapperRegistry.addMapper(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。

package org.apache.ibatis.binding;import java.io.Serializable;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.util.Map;import org.apache.ibatis.reflection.ExceptionUtil;import org.apache.ibatis.session.SqlSession;/** * @author Clinton Begin * @author Eduardo Macarron */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;  }  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    if (Object.class.equals(method.getDeclaringClass())) {      try {        return method.invoke(this, 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;  }}

 

要使用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方法。

 

MyBatis架構中Mapper映射配置的使用及原理解析(七) MapperProxy,MapperProxyFactory

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.