[TOC]
1. 回顾 Mybatis 执行 sql 的流程
在之前的代码中咱们的运行过程再梳理一下, 首先咱们执行 Test,调用 dao 接口办法
接口的定义:
调用接口的实现类办法:
最初才是调用真正的 sql:
下面的代码是在接口实现类外面本人去执行 id,查找并执行 mapper 文件外面的 sql,那么咱们想是不是能够缩小一步呢?
如果咱们不必本人实现接口,只须要将接口的名字和 mapper 文件的 namespace 对应起来,将接口外面的办法名与 sql 语句标签的 id 对应起来是不是就能够了呢?
事实上,mybatis 提供了这样的做法,这就是 mapper 动静代理。
2.mapper 动静代理怎么写?
首先主配置文件(Mybatis.xml
),在外面配置数据库连贯信息,注册须要扫描的 mapper
文件:
定义数据库查问的接口,外面每一个接口的名字很重要,须要和 mapper
外面每一条 sql
对应起来:
定义 mapper
文件(namespace 是接口的全限定类名):
那咱们在应用的时候,须要应用 sqlSession.getMapper()
办法,外面传入的是接口,意思是通过 接口的全限定名 ,也就是后面在mapper.xml
文件外面配置的命名空间 nameSpace
, 这样一来,就是获取到了代理类,将dao
和mapper.xml
文件关联起来了,而每条 sql
的id
与咱们的接口办法名字对应起来)
咱们在后面还写到过一个 selectStudentMap()
办法,然而外面调用的是和 SelectList()
一样的 sql
,在接口的实现类外面咱们本人解决了一下,然而当初应用主动实现的话,底层只会调用SelectOne()
或者 SelectList()
办法,所以这个办法会报错,如果承受类型是 list
,那么框架会主动应用selectList()
办法,否则就会抉择 selectOne()
这个办法。
在这里咱们应用的是返回的是 map
,所以主动抉择返回selectOne()
办法,那么就会报错。如果咱们须要应用主动返回 map
的话,能够本人定一个 map
,或者返回list
之后再解决,这个知识点前面再介绍,有趣味能够拜访:mybatis 的 mapper 返回 map 后果集
3.mapper 动静代理怎么做的?
打一个断点在 sqlSession.getMapper()
办法上:
咱们能够看到执行上面的接口办法 (接口SqlSession
的办法)
<T> T getMapper(Class<T> var1);
这是一个接口,咱们能够看到实现接口的有两个类,一个是 DefaultSqlSession
, 一个是SqlSessionManager
,咱们须要看的是DefaultSqlSession
上面的接口:
public <T> T getMapper(Class<T> type) {return this.configuration.getMapper(type, this);
}
咱们晓得,在创立 sqlsession
的时候,confiiguration
这个配置对象曾经创立实现。跟进去, 这是应用 mapper
注册器对象的 getMapper()
办法,将以后的 sqlSession
对象传递进去:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession);
}
咱们跟进去源码,能够发现外面应用 knownMappers.get(type)
来获取 mapper
代理工厂,这个 konwnMappers
是一个 hashMap
,这个hashMap
外面曾经初始化了 mapperProxyFactory
对象了,获取到工厂对象之后,再去应用 sqlSession
实例化:
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);
}
}
实例化的时候,应用了 mapper
动静代理:
public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface}, mapperProxy);
}
从上面的 debug 后果中咱们能够看到,这是动静代理的后果, 咱们看到的是 dao
,然而动静代理对这个dao
做了加强,实则是一个mapperProxy
。
【作者简介】:
秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使迟缓,驰而不息。这个世界心愿所有都很快,更快,然而我心愿本人能走好每一步,写好每一篇文章,期待和你们一起交换。
此文章仅代表本人(本菜鸟)学习积攒记录,或者学习笔记,如有侵权,请分割作者核实删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有谬误之处,还望指出,感激不尽~