mybatis源碼閱讀(四):mapper(dao)實例化

在開始分析以前,先來了解一下這個模塊中的核心組件之間的關係,如圖:sql

1.MapperRegistry&MapperProxyFactory

MapperRegistry是Mapper接口及其對應的代理對象工程的註冊中心,Configuration是Mybatis全局性的配置對象,在初始化的過程當中,全部配置信息會被解析成相應的對象並記錄到Configuration對象中,這在以前也詳細介紹了。Configuration.mapperRegistry字段記錄當前使用的MapperRegistry對象,數組

public class MapperRegistry {

  // 全局惟一的配置對象,其中包含了全部的配置信息
  private final Configuration config;
  // 記錄Mapper接口與對應MapperProxyFactory之間的關係
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
}

 

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);
      }
    }
  }
}
public <T> void addMapper(Class<T> type) {
  mapperRegistry.addMapper(type);
}
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));
      // 註解處理
      MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
      parser.parse();
      loadCompleted = true;
    } finally {
      if (!loadCompleted) {
        knownMappers.remove(type);
      }
    }
  }
}

在須要執行SQL語句時,會先獲取mapper藉口的代理對象,例如:緩存

@Test
public void findUserById() {
    SqlSession sqlSession = getSessionFactory().openSession();
    UserDao userMapper = sqlSession.getMapper(UserDao.class);
    User user = userMapper.findUserById(1);
    Assert.assertNotNull("沒找到數據", user);
}

DefaultSqlSession類中方法以下,其實是經過JDK動態代理生成的代理對象app

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

Configuration類方法以下:ide

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

MapperRegistry類中方法以下:ui

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  //查找指定type對象的MapperProxyFactory對象
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  if (mapperProxyFactory == null) {//若是爲空拋出異常
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {
      // 建立實現了type接口的代理對象
    return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}

MapperProxyFactory主要負責建立代理對象this

@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<T>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}

2.MapperProxy

MapperProxy實現了InvocationHandler接口,對動態代理的能夠先去了解這篇文章http://www.javashuo.com/article/p-aifratub-hk.htmlspa

public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  // 記錄關聯的SQLSession對象
  private final SqlSession sqlSession;
  // mapper接口對應的class對象
  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 {
      // 若是目標方法是Object類繼承來的,直接調用目標方法
      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);
    // 執行sql 語句
    return mapperMethod.execute(sqlSession, args);
    }
 }

3.MapperMethod

MapperMethod中封裝了Mapper接口中對應方法的信息,以及對應SQL語句的信息,.net

public class MapperMethod {

  // 記錄SQL語句的名稱和類型
  private final SqlCommand command;
  // mapper接口中對應方法的相關信息
  private final MethodSignature method;

  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    this.command = new SqlCommand(config, mapperInterface, method);
    this.method = new MethodSignature(config, mapperInterface, method);
  }

  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
      Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          // 處理返回值爲void ,ResultSet 經過ResultHand處理的方法
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          // 處理返回值爲集合或者數組的方法
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          // 處理返回值爲map的方法
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          // 處理返回值爲cursor的方法
          result = executeForCursor(sqlSession, args);
        } else {
          // 處理返回值爲單一對象的方法
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
}
相關文章
相關標籤/搜索