欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatis源碼剖析之Mapper代理方式詳解

 更新時(shí)間:2022年07月18日 08:17:39   作者:共飲一杯無(wú)  
這篇文章主要為大家詳細(xì)介紹了MyBatis中Mapper代理的方式,文中將通過(guò)源碼為大家進(jìn)行詳細(xì)的剖析,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

具體代碼如下:

//前三步都相同
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//這?不再調(diào)?SqlSession的api,?是獲得了接?對(duì)象,調(diào)?接?中的?法。
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//模擬ids的數(shù)據(jù)
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
List<User> userList = mapper.findByIds(ids);

思考?個(gè)問(wèn)題,通常的Mapper接?我們都沒(méi)有實(shí)現(xiàn)的?法卻可以使?,是為什么呢? 答案很簡(jiǎn)單:動(dòng)態(tài)代理

public class Configuration {  
    protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
}

public class MapperRegistry {
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
}

開(kāi)始之前介紹?下MyBatis初始化時(shí)對(duì)接?的處理:MapperRegistry是Configuration中的?個(gè)屬性,它內(nèi)部維護(hù)?個(gè)HashMap?于存放mapper接?的??類,每個(gè)接?對(duì)應(yīng)?個(gè)??類。mappers中可以配置接?的包路徑,或者某個(gè)具體的接?類。

<mappers>
  <mapper class="com.zjq.mapper.UserMapper"/>
  <package name="com.zjq.mapper"/>
</mappers>

當(dāng)解析mappers標(biāo)簽時(shí),它會(huì)判斷解析到的是mapper配置?件時(shí),會(huì)再將對(duì)應(yīng)配置?件中的增刪改查標(biāo)簽 封裝成MappedStatement對(duì)象,存?mappedStatements中。(上?介紹了)當(dāng)判斷解析到接?時(shí),會(huì)建此接?對(duì)應(yīng)的MapperProxyFactory對(duì)象,存?HashMap中,key =接?的字節(jié)碼對(duì)象,value =此接?對(duì)應(yīng)MapperProxyFactory對(duì)象。

源碼剖析-getmapper()

進(jìn)? sqlSession.getMapper(UserMapper.class )中

public interface SqlSession extends Closeable {
      //調(diào)用configuration中的getMapper
      <T> T getMapper(Class<T> type);
}

public class DefaultSqlSession implements SqlSession {
  @Override
  public <T> T getMapper(Class<T> type) {
    //調(diào)用configuration 中的getMapper
    return configuration.<T>getMapper(type, this);
  }
}

public class Configuration {
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //調(diào)用MapperRegistry 中的getMapper
    return mapperRegistry.getMapper(type, sqlSession);
  }
}

public class MapperRegistry {
  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //從 MapperRegistry 中的 HashMap 中拿 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 {
      //調(diào)用MapperProxyFactory的newInstance通過(guò)動(dòng)態(tài)代理???成實(shí)例
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
}


public class MapperProxyFactory<T> {
  public T newInstance(SqlSession sqlSession) {
    //創(chuàng)建了 JDK動(dòng)態(tài)代理的Handler類
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    //調(diào)?了重載?法
    return newInstance(mapperProxy);
  }
   
  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
}

//MapperProxy 類,實(shí)現(xiàn)了 InvocationHandler 接?
public class MapperProxy<T> implements InvocationHandler, Serializable {
  //省略部分源碼
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;
    
  //構(gòu)造,傳?了 SqlSession,說(shuō)明每個(gè)session中的代理對(duì)象的不同的!  
  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }
  
   //省略部分源碼
}

源碼剖析-invoke()

在動(dòng)態(tài)代理返回了示例后,我們就可以直接調(diào)?mapper類中的?法了,但代理對(duì)象調(diào)??法,執(zhí)?是在MapperProxy中的invoke?法中。

public class MapperProxy<T> implements InvocationHandler, Serializable { 
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      //如果是Object定義的?法,直接調(diào)?
      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 對(duì)象
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //重點(diǎn)在這:最終調(diào)?了MapperMethod執(zhí)?的?法
    return mapperMethod.execute(sqlSession, args);
  }
}

進(jìn)?execute?法:

public class MapperMethod { 
  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //判斷mapper中的?法類型,最終調(diào)?的還是SqlSession中的?法 switch(command.getType()) 
    switch (command.getType()) {
      case INSERT: {
        //轉(zhuǎn)換參數(shù)
        Object param = method.convertArgsToSqlCommandParam(args);
        //執(zhí)?INSERT操作
        //轉(zhuǎn)換rowCount
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        //轉(zhuǎn)換參數(shù)
        Object param = method.convertArgsToSqlCommandParam(args);
        // 轉(zhuǎn)換 rowCount
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        //轉(zhuǎn)換參數(shù)
        Object param = method.convertArgsToSqlCommandParam(args);
        // 轉(zhuǎn)換 rowCount
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        //?返回,并且有ResultHandler?法參數(shù),則將查詢的結(jié)果,提交給 ResultHandler 進(jìn)?處理
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        //執(zhí)?查詢,返回列表
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        //執(zhí)?查詢,返回Map
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        //執(zhí)?查詢,返回Cursor
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        //執(zhí)?查詢,返回單個(gè)對(duì)象
        } else {
          //轉(zhuǎn)換參數(shù)
          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());
    }
    //返回結(jié)果為null,并且返回類型為基本類型,則拋出BindingException異常
    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() + ").");
    }
    //返回結(jié)果
    return result;
  }
}

到此這篇關(guān)于MyBatis源碼剖析之Mapper代理方式詳解的文章就介紹到這了,更多相關(guān)MyBatis Mapper代理方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論