mybatis系列之获取mapper.xml配置文件中的sql
hello~各位读者好,我是鸭血粉丝(大家可以称呼我为「阿粉」)。今天,阿粉带着大家来了解一下获取 mapper.xml 配置文件中的sql上期回顾首先,我们还是回顾一下上篇文件的内容。...
hello~各位读者好,我是鸭血粉丝(大家可以称呼我为「阿粉」)。今天,阿粉带着大家来了解一下获取
mapper.xml
配置文件中的sql
上期回顾
首先,我们还是回顾一下上篇文件的内容。先看下这个测试类,大家还有印象吗:
public class MybatisTest {
@Test
public void testSelect() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
try {
FruitMapper mapper = session.getMapper(FruitMapper.class);
Fruit fruit = mapper.findById(1L);
System.out.println(fruit);
} finally {
session.close();
}
}
}
上篇源码分析讲了 获取mybatis
的 mapper
接口,它是一个代理类。这次,我们来了解下 获取 mapper.xml
配置文件中的sql。
初始化做了什么事
阿粉其实第一篇的时候就已经讲过了 mybatis
的初始化,但是已经有一段时间了。这篇文章又正好要讲怎么获取 mapper.xml
里面的 sql,所有这里阿粉再简单说下mapper.xml
的初始化。
2.1 mapper.xml
首先看下阿粉测试的mapper.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="com.cl.mybatis.mapper.FruitMapper">
<sql id="fruit">id,name </sql>
<select id="findById" resultType="fruit">
select <include refid="fruit"/> from fruit where id =#{id}
</select>
</mapper>
2.2 Configuration -> mappedStatements
然后,所有解析的 xml 都会放到Configuration
这个类里面。那么跟着阿粉来看下mapper.xml
解析之后是个什么东西。
这里阿粉就直接给出结果,就不再次去走下初始化流程了。
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
mappedStatements
是 Configuration
类里面的一个属性,这个就是用来放我们的 mapper.xml
里面的信息。我们来看下具体是怎么放的。
首先在 SqlSession session = sqlSessionFactory.openSession(); 这段代码打个断点,sqlSessionFactory 已经构建了,里面有一个 Configuration
属性。看下阿粉截的图。
mappedStatements 是一个map,key 等于com.cl.mybatis.mapper.FruitMapper.findById
,这个是什么?是不是就是mapper.xml
类的全路径,加上 <select>
标签的 id 。然后 value 是一个 MappedStatement 对象,每个 <select | update | insert | delete>
会解析成一个 MappedStatement
对象。MappedStatement
对象里面有一个 sqlSource
属性,这个放的就是我们自己写的 sql 。
现在是不是很清楚了,只要我们获取到com.cl.mybatis.mapper.FruitMapper.findById
这个 key,是不是就可以获取到对应的 sql,那怎么获取这个key呢?
获取对应的key
3.1 代理类 -> h
还记得阿粉上一篇文章吗?获取 mapper 接口,返回的是一个代理对象,使用的是JDK的动态代理。看下创建代理类的方法。
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
mapperProxy 这个是我们的 h 类,h 类里面肯定有一个 invoke 方法。首先什么是 h 类?我们看下 newProxyInstance 方法。
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
。。。
}
实现 InvocationHandler 接口的类就是 h类。还是不懂的可以去看下 JDK 实现的动态代理模式,阿粉这里就不继续深入了。
3.2 获取 key
现在们去看下 h类里面的 invoke 方法。MapperProxy -> invoke
@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 if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
我们看下倒数第二行的 cachedMapperMethod 方法,ctrl + 左键点进去。
private MapperMethod cachedMapperMethod(Method method) {
return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
看下这句代码 MapperMethod(mapperInterface,method,sqlSession.getConfiguration())) 我们来猜测一下,mapperInterface 是不是我们的 mapper 接口,这个能不能获取到 mapper
接口的全路径,method 是不是我们当前调用的方法 ,看下阿粉的测试方法:Fruit fruit = mapper.findById(1L) ,获取 findById() 这个方法的名字,就是 "findById",一拼接就获取到了key,对不对?我们带正式一下,ctrl + 左键 MapperMethod。
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
在倒数第一行代码上打个断点。我们看下 command 这个成员变量。
看,我们的 key 是不是拿到了,那么 sql 是不是也拿到了。
总结
最后,阿粉在来梳理下这个流程:
mybatis
初始化的时候,会将mapper.xml
解析放到Configuration
类的mappedStatements
属性上。mappedStatements
是一个map ,它的 value 是一个对象,对象里面的一个属性存了我们写的 sql 语句。要想获取 value 必须找到对应的 key。获取 key 是通过 JDK代理模式实现的,代理 mapper 接口,在执行这个接口的方法的时候,就会获取到当前接口的全路径和当前方法的名字。
好了,今天阿粉就讲到这里,下次阿粉会带着到家去了解一下,获取到 sql 之后,mybatis是怎么去执行 sql 的。我们下次 mybatis 源码分析再见。
最后说两句(求关注)
最近大家应该发现微信公众号信息流改版了吧,再也不是按照时间顺序展示了。这就对阿粉这样的坚持的原创小号主,可以说非常打击,阅读量直线下降,正反馈持续减弱。
所以看完文章,哥哥姐姐们给阿粉来个在看吧,让阿粉拥有更加大的动力,写出更好的文章,拒绝白嫖,来点正反馈呗~。
如果想在第一时间收到阿粉的文章,不被公号的信息流影响,那么可以给Java极客技术设为一个星标。
最后感谢各位的阅读,才疏学浅,难免存在纰漏,如果你发现错误的地方,由于本号没有留言功能,还请你在后台留言指出,我对其加以修改。
最后谢谢大家支持~
最最后,重要的事再说一篇~
快来关注我呀~
快来关注我呀~
快来关注我呀~
< END >
如果大家喜欢我们的文章,欢迎大家转发,点击在看让更多的人看到。也欢迎大家热爱技术和学习的朋友加入的我们的知识星球当中,我们共同成长,进步。
更多推荐
所有评论(0)