mybatis系列之获取mapper.xml配置文件中的sql

栏目: IT技术 · 发布时间: 4年前

内容简介:hello~各位读者好,我是鸭血粉丝(大家可以称呼我为「阿粉」)。今天,阿粉带着大家来了解一下获取首先,我们还是回顾一下上篇文件的类容。先看下这个测试类,大家还有印象吗:上篇源码分析讲了 获取

hello~各位读者好,我是鸭血粉丝(大家可以称呼我为「阿粉」)。今天,阿粉带着大家来了解一下获取 mapper.xml 配置文件中的sql

1.上期回顾

首先,我们还是回顾一下上篇文件的类容。先看下这个测试类,大家还有印象吗:

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();
        }
    }
}

上篇源码分析讲了 获取 mybatismapper 接口,它是一个代理类。这次,我们来了解下 获取 mapper.xml 配置文件中的sql。

2. 初始化做了什么事

阿粉其实第一篇的时候就已经讲过了 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());

mappedStatementsConfiguration 类里面的一个属性,这个就是用来放我们的 mapper.xml 里面的信息。我们来看下具体是怎么放的。

首先在 SqlSession session = sqlSessionFactory.openSession(); 这段代码打个断点,sqlSessionFactory 已经构建了,里面有一个 Configuration 属性。看下阿粉截的图。

mybatis系列之获取mapper.xml配置文件中的sql

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呢?

3. 获取对应的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 这个成员变量。

mybatis系列之获取mapper.xml配置文件中的sql

看,我们的 key 是不是拿到了,那么 sql 是不是也拿到了。

总结

最后,阿粉在来梳理下这个流程:

  • mybatis 初始化的时候,会将 mapper.xml 解析放到 Configuration 类的 mappedStatements 属性上。
  • mappedStatements 是一个map ,它的 value 是一个对象,对象里面的一个属性存了我们写的 sql 语句。要想获取 value 必须找到对应的 key。
  • 获取 key 是通过 JDK代理模式实现的,代理 mapper 接口,在执行这个接口的方法的时候,就会获取到当前接口的全路径和当前方法的名字。

好了,今天阿粉就讲到这里,下次阿粉会带着到家去了解一下,获取到 sql 之后,mybatis是怎么去执行 sql 的。我们下次 mybatis 源码分析再见。


以上所述就是小编给大家介绍的《mybatis系列之获取mapper.xml配置文件中的sql》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

云攻略

云攻略

马克·贝尼奥夫、卡莱尔·阿德勒 / 徐杰 / 海天出版社 / 2010年8月 / 36.00元

Apple、Google、甲骨文、腾讯 都已投入了云的怀抱, 你还在等什么? 快来加入我们! 最初,Salesforce.com 只是一间小小的租赁公寓 在短短10年内 它已成长为 世界上发展最快、最具创新力的 产业变革领导者 曾经,这是个软件为王的时代。 现在,这是个云计算的新时代。 NO SOFTWARE 抛弃软件的......一起来看看 《云攻略》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具