Mybatis中一个非常重要的组件是mapper, 它担任了dao的角色,是业务逻辑层和数据库层的桥梁。那么在Mybatis中它是如何实现的呢?
在Mybatis应用中,mapper一般配置在Mybatis配置文件中,如下所示:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="config.properties"/> <typeHandlers> <typeHandler javaType="string" jdbcType="VARCHAR" handler="com.secoo.typehandler.MyStringHandler"/> </typeHandlers> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="${db_driver}"/> <property name="url" value="${db_url}"/> <property name="username" value="${db_username}"/> <property name="password" value="${db_password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/secoo/UserMapper.xml" /> </mappers> </configuration>
在生成SqlSessionFactory时,XMLConfigBuilder会解析这个配置文件,将所有生成的mapper添加到Configuration对象中,这里实际上添加的并不是实际的mapper对象,而是MapperProxyFactory,实际的mapper只会在Session调用getMapper时才会生成,因为mapper在执行时需要依赖具体的Session,所以mapper是不可能在配置解析时候生成的。
当Session调用getMapper时,会生成MapperProxy并作为生成的代理类的InvocationHandler,在源码中有如下代码:
Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
这里MapperProxy实现了InvocationHandler接口,当调用我们自己实现的mapper所定义的接口时会调用MapperProxy的invoke接口,生成MapperMethod并调用其execute方法执行数据库操作