我们在使用mybatis时只定义了类似 ActorMapper 的接口,并没有编写实现这个接口的类,实际上mybatis在初始化时生成了这个接口的代理对象,这篇文章分析下mybatis在何时完成的这件事。
通过 org.apache.ibatis.session.SqlSession.getMapper 方法我们可以获得对象接口的代理类,下面分析下这段代码:
ActorMapper actorMapper = session.getMapper(ActorMapper.class);
org.apache.ibatis.session.defaults.DefaultSqlSession getMapper 方法,从以下代码可知,实际执行的是 configuration 的 getMapper 方法:
publicT getMapper(Class type) { return this.configuration.getMapper(type, this); }
org.apache.ibatis.session.Configuration getMapper 方法,如下 configuration调用的是 configuration 属性 MapperRegistry mapperRegistry 的方法,mapperRegistry 是在 org.apache.ibatis.builder.xml.XMLConfigBuilder 构造方法中初始化 Configuration过程中初始化的
publicT getMapper(Class type, SqlSession sqlSession) { return this.mapperRegistry.getMapper(type, sqlSession); }
org.apache.ibatis.binding.MapperRegistry
解析完 *Mapper.xml 后,MapperRegistry 中 knownMappers 属性已经填充好了对应 接口和 MapperProxyFactory 的键值对
public class MapperRegistry {
private final Configuration config;
private final Map, MapperProxyFactory>> knownMappers = new HashMap();
public T getMapper(Class type, SqlSession sqlSession) {
MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
// 生成 Mapper 的代理对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
}
org.apache.ibatis.binding.MapperProxyFactory
package org.apache.ibatis.binding; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.ibatis.binding.MapperProxy.MapperMethodInvoker; import org.apache.ibatis.session.SqlSession; public class MapperProxyFactory{ private final Class mapperInterface; private final Map methodCache = new ConcurrentHashMap(); public MapperProxyFactory(Class mapperInterface) { this.mapperInterface = mapperInterface; } public Class getMapperInterface() { return this.mapperInterface; } public Map getMethodCache() { return this.methodCache; } protected T newInstance(MapperProxy mapperProxy) { // 通过JDK动态代理的方式生成代理对象 return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); } // 生成代理对象 public T newInstance(SqlSession sqlSession) { MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache); return this.newInstance(mapperProxy); } }
org.apache.ibatis.binding.MapperProxy
如下:MapperProxy 实现了 InvocationHandler 接口
public class MapperProxyimplements InvocationHandler, Serializable { private static final long serialVersionUID = -4724728412955527868L; private static final int ALLOWED_MODES = 15; private static final Constructor lookupConstructor; private static final Method privateLookupInMethod; private final SqlSession sqlSession; private final Class mapperInterface; private final Map methodCache; public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) { this.sqlSession = sqlSession; this.mapperInterface = mapperInterface; this.methodCache = methodCache; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession); } catch (Throwable var5) { throw ExceptionUtil.unwrapThrowable(var5); } } }
当执行 selectOneActor 方法时实际调用 MapperProxy invoke 方法,最终从 configuration 中获取 SQL 并替换参数执行
publicList selectList(String statement, Object parameter, RowBounds rowBounds) { List var5; try { MappedStatement ms = this.configuration.getMappedStatement(statement); var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); } catch (Exception var9) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9); } finally { ErrorContext.instance().reset(); } return var5; }



