版本
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
mapper类是怎么保存的?
两个重要的类
MapperProxy
mybatis的mapper是通过jdk动态代理实现的,org.apache.ibatis.binding.MapperProxy 是 InvocationHandler 的实现类,调用mapper中的方法时,先执行 invoke 方法。
MapperMethod
Mapper类的方法,实际时调用了 MapperMethod 的 execute 方法。
生成代理对象的调用时序
-
SqlSession 的 getMapper(Class type) 为起点,返回的是 a mapper bound to this SqlSession。
-
调用 Configuration 的 getMapper(Class type, SqlSession sqlSession)。
-
调用 MapperRegistry 的 getMapper(Class type, SqlSession sqlSession):
根据 type 在 knownMappers(Map类型) 中获取 MapperProxyFactory 实例对象。
knownMappers 需要先完成初始化,要调用addMapper;knownMappers key为Class<?>,value为 MapperProxyFactory<?>。 -
调用 MapperProxyFactory 的 newInstance(SqlSession sqlSession) 生成并返回Mapper对象。具体如下:
(1):调用 new MapperProxy(sqlSession, mapperInterface, methodCache) 获取 InvocationHandler 的实现类 MapperProxy;
(2):调用 Proxy.newProxyInstance 返回jdk动态代理对象。
补充:MapperProxy调用invoke方法时,如果 methodCache 没有缓存,则先缓存。
MapperProxy#methodCache类型为Map<Method, MapperProxy.MapperMethodInvoker>。
methodCache是被保存在MapperProxy对应的MapperProxyFactory中。
MapperMethodInvoker 两个实现类的构造器参数分析
- 需要代理的方法
- 如果是default方法,返回的是 DefaultMethodInvoker 类型对象,其构造器参数是 MethodHandle。
- 如果不是default方法,返回的是 PlainMethodInvoker 类型对象,其构造器参数是 MapperMethod。
- 如果是 PlainMethodInvoker,最终调用的是 MapperMethod 的 execute 方法。
MapperMethod 的 execute 方法
如果Mapper调用的是select方法
处理参数后,调用 sqlSession 中的 select 方法,有三个实现类,
接下来可以了解,SqlSessionTemplate、SqlSessionManager有用到了装饰者模式,还有 DefaultSqlSession。
DefaultSqlSession 的 selectList 分析
- 通过 configuration 获取 MappedStatement。
- 调用 Executor 的 query。
MapperProxy只有一个构造方法
/**
* 实现了InvocationHandler。
*/
public class MapperProxy<T> implements InvocationHandler, Serializable {
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperProxy.MapperMethodInvoker> methodCache) {
this.sqlSession = sqlSession;
//MapperProxyFactory中只有这两个字段,methodCache 在调用本类的 cachedInvoker 时缓存的。
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
//获取缓存方法(没有则生成),然后调用。cachedInvoker返回的是 MapperMethodInvoker 对象。
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
/*
* 当前类中还包含了两个实现类
*/
interface MapperMethodInvoker {
Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable;
}
}
实例的创建在 MapperProxyFactory#newInstance
/**
* MapperProxyFactory一般是单例,所以methodCache是共享的。
* mapperInterface是final修饰的,methodCache存的是要和某个接口关联的。
*/
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethodInvoker> getMethodCache() {
return methodCache;
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
public class MapperRegistry {
private final Configuration config;
/*
* key 保存了用户自定义的 Mapper 接口,value 是相对应的 MapperProxyFactory,但需要被 Configuration # addMapper 先初始化。
* MapperProxyFactory 只是设置了 mapperInterface 属性,methodCache 中的元素是空的。
*/
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
public MapperRegistry(Configuration config) {
this.config = config;
}
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);
}
}
}
mybatis plus 中的 MybatisMapperMethod 对应 MapperMethod