org.apache.ibatis.bindingjava
封裝ibatis編程模型 ibatis編程模型中,SqlSession做爲sql執行的入口,實用方法爲sqlSession.selectOne(namespace+id, 參數列表)的形式(例:sqlSession.selectOne("com.enjoylearning.mybatis.mapper.TUserMapper.selectByPrimaryKey", 2)),不易於維護和閱讀sql
我的理解apache
- MapperRegistry的Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>(); key:mapper的Class對象 value:生產這個mapper的動態代理示例的工廠
- MapperProxyFactory:Map<Method, MapperMethod> methodCache key:方法的反射類 value 方法的信息(sql語句,入參,返回值)
public class MapperRegistry { private final Configuration config;//config對象,mybatis全局惟一的 //記錄了mapper接口與對應MapperProxyFactory之間的關係 private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>(); public MapperRegistry(Configuration config) { this.config = config; } @SuppressWarnings("unchecked") 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); }
/** * * 用於生成mapper接口動態代理的實例對象; * @author Lasse Voss */ public class MapperProxyFactory<T> { //mapper接口的class對象 private final Class<T> mapperInterface; //key是mapper接口中的某個方法的method對象,value是對應的MapperMethod,MapperMethod對象不記錄任何狀態信息,因此它能夠在多個代理對象之間共享 private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();
public class MapperMethod { //從configuration中獲取方法的命名空間.方法名以及SQL語句的類型 private final SqlCommand command; //封裝mapper接口方法的相關信息(入參,返回類型); private final MethodSignature method;
public class MapperProxyFactory<T> { //mapper接口的class對象 private final Class<T> mapperInterface; //key是mapper接口中的某個方法的method對象,value是對應的MapperMethod,MapperMethod對象不記錄任何狀態信息,因此它能夠在多個代理對象之間共享 private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>(); public MapperProxyFactory(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } public Class<T> getMapperInterface() { return mapperInterface; } public Map<Method, MapperMethod> getMethodCache() { return methodCache; } @SuppressWarnings("unchecked") protected T newInstance(MapperProxy<T> mapperProxy) { //建立實現了mapper接口的動態代理對象 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { //每次調用都會建立新的MapperProxy對象 final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } }
兩個newInstance方法生成mapper的動態代理對象MapperProxy編程
public class MapperProxy<T> implements InvocationHandler, Serializable { ....... @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) {//若是是Object自己的方法不加強 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); //調用execute方法執行sql return mapperMethod.execute(sqlSession, args); } private MapperMethod cachedMapperMethod(Method method) { return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())); }
從invoke方法能夠看出 是mapperMethod調用了execute方法數組
public class MapperMethod { ...... public Object execute(SqlSession sqlSession, Object[] args) { Object result; //根據sql語句類型以及接口返回的參數選擇調用不一樣的 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 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()) {//返回值爲遊標 result = executeForCursor(sqlSession, args); } else {//處理返回爲單一對象的狀況 //經過參數解析器解析解析參數 Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { result = OptionalUtil.ofNullable(result); } } 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; }
重點看 result = sqlSession.selectOne(command.getName(), param); 這裏使用了ibatis的用法緩存
mapperProxy作查詢依賴的仍是sqlSession.按照如今的代碼結構來講,若是緩存了mapperProxy,當sqlSession失效,mapperProxy也就失效了. 若是修改代結構,那麼sqlSession就要做爲查詢參數mybatis
// 本來 TUser user = mapper.selectByPrimaryKey(2); // 修改後的寫法 TUser user = mapper.selectByPrimaryKey(sqslSession,2);