目录
一、缘起
前三篇的文章主要介绍了Mybatis配置以及在spring整合中核心组件SqlSessionFactory对象的创建过程(其中包括了相关子节点的加载,Mapper.xml的加载)。这篇博文主要用来介绍针对Mybatis的curd操作的整个执行流程。因为mybatis单机是对jdbc操作的封装,笔者的分析只到jdbc操作流程(算是mybatis源码的浅尝辄止)。
二、示例代码
1、mybatis单独测试操作代码
@Test
public void testMapper() throws IOException {
String resource="mybatis-config.xml";
//以流的方式获取recource(mybatis的环境配置文件)
InputStream inputStream= Resources.getResourceAsStream(resource);
//创建会话工厂
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession
SqlSession sqlSession= sqlSessionFactory.openSession();
//从创建的SqlSession对象中获取Mapper对象 (这个是核心,因为只有拿到该对象的Mapper对象
//(其实是Mapper接口的代理MapperProxy对象实例))
BookMapper bookMapper = sqlSession.getMapper(BookMapper.class);
int bookId = 1000;
BookExample bookExample = new BookExample();
bookExample.createCriteria().andIdEqualTo(bookId);
List<Book> books = bookMapper.selectByExample(bookExample);
}
2、spring与mybatis的整合操作代码
@Autowired
private BookMapper bookDao;
@Test
public void testQueryById() throws Exception {
int bookId = 1000;
BookExample bookExample = new BookExample();
bookExample.createCriteria().andIdEqualTo(bookId);
List<Book> books = bookDao.selectByExample(bookExample);
}
3、 总结
如上两种方式前者使用代码显示的从SqlSession对象中获取Mapper代理对象,后者则是在spring容器启动后将Mapper对象创建放入Spring容器中进行托管。这里有个疑问在于我们编写的XxxMapper为接口,但是在使用过程中初始化了其相应的Mapper代理对象。这里我们就来分析一下。
3.1、MapperProxy对象
这里不卖关子了,其实Mybatis为我们动态的生成了XxxMapper对象的的代理对象类为MapperProxy,熟悉JDK动态代理的同学都知道接口中所有的实现都是调用实现了InvocationHandler对象的invoke()方法,我们所有对XxxMapper接口中方法的调用最终都会调用invoke()方法。上面的两个测试(一个单独测试,一个spring整合测试)该对象生成过程之间略有差异,前者是使用DefaultSqlSession的getMapper方法来生成,而后者则是使用SqlSessionTemplate对象的getMapper()方法生成。这里我们来对该MapperProxy对象初始化来做分析。
public <T> T getMapper(Class<T> type) {
//通过Configuration对象获取其中的mapper
return this.getConfiguration().getMapper(type, this);
}
configuration对象是我们mybatis的所有配置的对象,通过调用其getMapper()方法来获取MapperProxy,但是实际操作是被委托给了MapperRegistry对象。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//通过configuration对象中的MapperRegistry对象调用其中的getMapper方法
return mapperRegistry.getMapper(type, sqlSession);
}
mapperRegistry根据对应的XxxMapper类class信息以及对应的mybatis会话sqlSession对象来获取dao层代理对象。还使用到了我们初始化Mapper.xml对象的时候将其以 XxxMapper className为key,MapperProxyFactory为value的形式存放在Map类型的结构对象knownMappers中,所以此处获取到对应的MapperProxyFactory对象(该对象中包含了XxxMapper接口类信息),通过Jdk动态代理生成XxxMapper接口的动态dialing对象
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//从map容器中获取MapperProxyFactory对象信息
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//调用map中获取的MapperProxyFactory对象 实例化Mapper动态代理对想
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
//JDK动态代理实例化dao接口对象
protected T newInstance(MapperProxy<T> mapperProxy) {
//jdk动态代理
return (T) Proxy.ne