一、思路
背景: mybatis 3.2.8+spring 4.3.2
- mapper的初始化过程。
- MapperProxy的执行过程。
二、mapper的初始化过程
请参考上一篇博客Mybatis系列之MapperRegister,关于spring是如何获取mapper对象的,这里就不赘述了。
三、MapperProxy的执行过程
我们用一个小例子来讲解,我们从spring上下文中拿到PersonMapper这个bean,然后调用它的count()方法,拿到结果输出到控制台。
PersonMapper
public interface PersonMapper {
int count();
}
PersonMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.com.bsfit.mapper.PersonMapper">
<select id="count" resultType="int">
select count(1) from t1
</select>
</mapper>
Main
@Test
public void testBeanGet() {
ApplicationContext context = new FileSystemXmlApplicationContext("classpath:spring.xml");
PersonMapper mapper = (PersonMapper) context.getBean("personMapper");
int count = mapper.count();
System.out.println(count);
}
说完上面的例子后,我们就来分析它背后的执行原理。
根据 第二节的信息我们知道我们拿到PersonMapper的Bean是一个PersonMapper接口的实现类,而这个实现类就是MapperProxy的一个代理类。拿到这个bean后,可以在控制台输出mapper.getClass()结果观察下,会发现它类似下面的输出,是一个JDK的代理类。
com.sun.proxy.$Proxy10
我们在看一下MapperProxy类的类结构,它实现了InvocationHandler接口,这个接口正是JDK代理类所需要实现的,代理类真正执行方法的时候会调用MapperProxy实现的 public Object invoke(Object proxy, Method method, Object[] args) 方法
MapperProxy类结构
下面我们来分析下MapperProxy实现的invoke方法,根据调用的mapper的方法找到对应的MapperMethod实例,之后开始真正执行sql。
public class MapperProxy<T> implements InvocationHandler, Serializable {
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 如果mapper调用的方法是object类声明的,则直接调用。
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
// 根据要调用的mapper方法(在我们的例子中是count())查询应对的MapperMethod实例
final MapperMethod mapperMethod = cachedMapperMethod(method);
// 获取到MapperMethod实例后,开始真正的执行sql
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
// 这里做了一层MapperMethod的缓存
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}
好了,到这里就结束了今天分享,下次我们再来看看MapperMethod具体是怎么来执行sql的。