mybatis运行源代码
Mybatis可以把Mapper.xml文件直接映射到对应的接口,调用接口方法会自动去Mapper.xml文件中找到对应的标签,这个功能就是利用java的动态代理在binding包中实现的。
一、注册Mapper
在初始化时会把获取到的Mapper接口注册到MapperRegistry,注册的时候创建一个Mapper代理工厂,这个工厂通过JDK的代理创建一个执行对象,创建代理需要的InvocationHandler为MapperProxy
public class MapperRegistry { public <T> T getMapper(Class<T> type, SqlSession sqlSession) { //取出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 { //创建代理 return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } } } //创建代理的工厂 public class MapperProxyFactory<T> { /** * 需要创建代理的接口 */ private final Class<T> mapperInterface; /** * 执行方法的缓存,不需要每次都创建MapperMethod */ private Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>(); 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) { //创建代理, InvocationHanderl是MapperProxy return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } /** * 传人sqlSession创建代理 * @param sqlSession * @return */ public T newInstance(SqlSession sqlSession) { //把代理执行需要用到的对象传入 final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } }
二、获取接口对象
从knownMappers中根据接口类型取出对应的代理创建工厂,用该工厂创建代理。
-
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 { //如果方法是Object里面的则直接调用方法 if (Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } //获取执行方法的封装对象 final MapperMethod mapperMethod = cachedMapperMethod(method); //里面就是找到对应的sql 执行sql语句 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; } }
三、调用接口方法
调用代理方法会进入到MapperProxy的public Object invoke(Object proxy, Method method, Object[] args)方法
-
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 { //如果方法是Object里面的则直接调用方法 if (Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } //获取执行方法的封装对象 final MapperMethod mapperMethod = cachedMapperMethod(method); //里面就是找到对应的sql 执行sql语句 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; } }
最终执行sql会进入到MapperMethod中execute方法:
-
public class MapperMethod { private final SqlCommand command; private final MethodSignature method; public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) { //SqlCommand封装该接口方法需要执行sql的相关属性,如:id(name), 类型 this.command = new SqlCommand(config, mapperInterface, method); //执行方法特性进行封装,用于构造sql参数,判断执行sql逻辑走哪条分支 this.method = new MethodSignature(config, method); } public Object execute(SqlSession sqlSession, Object[] args) { Object result; //先找到对应的执行sql类型, sqlSession会调用不同方法 if (SqlCommandType.INSERT == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); } else if (SqlCommandType.UPDATE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); } else if (SqlCommandType.DELETE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); } else if (SqlCommandType.SELECT == command.getType()) {//如果是查询, 需要对返回做判断处理 //根据方法的特性判断进入哪个执行分支 if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { result = executeForMany(sqlSession, args); } else if (method.returnsMap()) { result = executeForMap(sqlSession, args); } else { //只查一条数据 Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); } } else { 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; }
}
上面就是根据接口、方法、配置参数找到对应的执行sql,并构造参数,解析执行结果,具体sql执行在sqlSession流程里面,后面再看。
没有停止的脚步,只有倒下去的脚步