首先我们来看看mybatis简单的使用方法.
我们需要配置一个UserDao.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.xiaoyu.dao.UserDao">
<select id="getUser" resultType="com.xiaoyu.entity.User">
select
a.id as id,
a.name as name,
from biz_user as a
where a.id =#{userId}
</select>
然后我们需要有个dao层接口,并使用spring的注解@Repository(高版本好像注解都不需要了)
@Repository
public class UserDao {
User getUser(String userId);
}
这样我们就可以使用mybatis了,但是一方面我们会乐见于其使用的方便性,另一方面也可能会疑惑为什么我们的dao层(或mapper层)只需要写好一个接口就可以了,而完全没有任何实现.mybatis是如何去实现以及执行xml文件中的sql的了.我们接下来就研究下.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring.xml" })
public class TestService {
@Autowired
private UserDao userDao;
@Test
public void testUser() {
User a = userDao.getUser("1");
a.toString();
}
}
我们写个简单的测试类并进行debug,可以看到代码会进入org.apache.ibatis.binding.MapperProxy类中调用方法.
顾名思义,这个MapperProxy是个代理类,并且实现了InvocationHandler.
public class MapperProxy<T> implements InvocationHandler, Serializable {}
其实从这里我们就可以想到,实现的原理就是用到了动态代理.也就是实际调用的是spring帮我们生成的代理对象.
好像就是这么回事?但是这样显得浅尝辄止,如何生成代理对象,以及生成了怎样的代理对象的才是我们应该知道的.
之前我一篇文章讲过spring扩展的问题.也同样适用于mybatis.我们在不深究之前可以大致想下处理流程.肯定是mybatis通过spring的扩展后,在启动的时候,spring按规则扫描mybatis的xml,并解析最后生成了一个代理对象存入spring中以供使用.所以我们来看下mybatis在spring启动的时候都做了什么吧.
在进行spring扩展的时候,我们需要创建spring.handlers文件,因此我们只需要在mybatis-spring-1.2.2.jar(当然我用的是这个版本的jar)中找到即可.
http\://mybatis.org/schema/mybatis-spring=org.mybatis.spring.config.NamespaceHandler
核心类已经列出来了,我们看看NamespaceHandler是怎么处理的吧.
public class NamespaceHandler extends NamespaceHandlerSupport {
/**
* {@inheritDoc}
*/
public void init() {
registerBeanDefinitionParser("scan", new MapperScannerBeanDefinitionParser(