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