
找到 Statement ID 有两种方式:
由于接口名称跟 Mapper.xml 的 namespace 是对应的, 接口的方法跟 statement ID 也都是对应的,所以根据方法名就能找到对应的要执行的 SQL。
DefaultSqlSession.getMapper() 调用了 Configuration.getMapper() 。 Configuration.getMapper() 又调用了 MapperRegistry.getMapper()
在解析 mapper 标签和 Mapper.xml 的时候,已经把接口类型和类型对应的 MapperProxyFactory 放到了一个 Map 中。 获取 Mapper 代理对象, 实际上是从 Map 中获取对应的工厂类后,调用以下方法创建对象:
最终通过代理模式返回代理对象:
JDK 动态代理代理,在实现了 InvocationHandler 的代理类里面,需要传入一个被 代理对象的实现类。
MyBatis 的动态代理不需要实现类的原因:我们只需要根据接口类型+方法的名称, 就可以找到 Statement ID 了,而唯一要做的一件事情也是这件,所以 不需要实现类 。在 MapperProxy 里面直接执行逻辑(也就是执行 SQL)就可以。
获得 Mapper 对象的过程, 实质 上是获取了一个 MapperProxy 的代理对象。 MapperProxy 中有 sqlSession、mapperInterface、methodCache。
可以用对应Mapper类,里面的方法名是对应的sql语句的ID名,这个可以去调用;还有一种,就是不用Mapper类,可以直接用xml的文件名.id名获取的方式,这个方式要有像SqlSessionTemplate这样的类,提前定义好方法获取方式,然后调用就可以了入口:一般会在DAO层配置中,比如下面是我的配置
在这里面,我们配置了id为sqlSessionFactory的bean。那么这也是我们的入口
由此可以看出,id为sqlSessionFactory的bean默认是DefaultSqlSessionFactory。Mybatis的官方推荐,SqlSessionFactory最好是做成单例的,不需要频繁创建。
通过api获取session的方式
那么我们就看DefaultSqlSessionFactory.openSession方法,如下
再看DefaultSqlSession.getMapper方法
这个 configuration 对象是在哪里创建,又是哪里传入的呢?其实是从一开始的 SqlSessionFactoryBean 中创建好后,赋值给 SqlSessionFactoryBuilder 的build的方法参数,一路传到了 DefaultSqlSession 中。也就是说 configuration 是隶属于 DefaultSqlSessionFactory 的,生命周期很长。
那 configuration 究竟有什么呢?
原来,所有的Mapper接口被扫描后,都会被存储在Configuration的mapperRegistry里的Map中。而且 key = Mapper class value = 创建当前Mapper的工厂 。
接着看 configuration.getMapper(..) 方法
那我们知道了 knownMappers.get(type) 返回的是一个创建Mapper的工厂 MapperProxyFactory 。
接下来我们看看 MapperProxyFactory 是如何创建的。直接看 MapperProxyFactory 的 newInstance(SqlSession sqlSession) 方法
可以清楚的看到,通过jdk的动态代理创建了代理类。那么我们需要关注一下,代理类的InvocationHandler做了哪些事情
这里需要注意methodCache这个Map,不是保存在本类里的。看MapperProxy的有参构造传进来的。那么谁创建的MapperProxy呢?上面我们说了是Mapper对应的Mapper工厂MapperProxyFactory。这个对象也是保存在 Configuration 中,生命周期很长。
这就解释了,为什么 官网上推荐,让Mapper的实现类 用后就可以舍弃(做局部变量),但是这样每次都去创建难道不耗时,答案是不耗时,因为核心的 MapperMethod 都已经被缓存起来了。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)