MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
那么我比较困惑的一点是,mybatis的mapper接口并没有任何实现它的实例,那它是怎么利用动态代理来进行mapper xml与接口的连接呢?下面我将从源码成名说明一下整个流程,同时将会给一个简单的例子来说明它实现的原理。
先来看一段例子:
请注意上面的例子,HelloImpl并未实现IHello,所以在DynaProxy中的invoke方法中不能调用method.invoke(Object obj, Object[] args),因为Java的动态代理机制要求obj上面的method调用的前提是obj实现了接口。此处虽然用了反射中的动态代理结构来组织代码实际上,此例子并非动态代理,这样就做到了IHello在没有任何实现的情况下,获得返回值。这主要就是MyBatis-3的mapper接口和xml的连接原理。
下面来翻一下MyBatis的源码,便于大家今后更方面的阅读。
MyBatis-3的使用,伪代码表示
mapper类
关于此段代码的配置文件
DefaultSqlSession: SqlSession的子类,定义一些列的数据库操作。
XMLConfigBuilder : 读取mybatis-config.xml,并将xml中配置的内容映射成相应的java代码。
XMLMapperBuilder:读取AccountSecurityMaster.xml,并将其中的mapper的接口映射成MapperProxyFactory,并保存在MapperRegistry中。
Configuration:用来操作配置的一系列内容
MapperRegistry:处理与保持xml中Mapper对应的MapperProxyFactory。
MapperProxyFactory:创建mapper的接口的伪实例
MapperProxy:负责代理mapper的接口,并在invoke方法内返回MapperMethod的执行结果
MapperMethod:此类用于将AccountSecurityMaster.xml中的insert,update,delete,select配置直接映射成jdbc的statement操作。
那么我比较困惑的一点是,mybatis的mapper接口并没有任何实现它的实例,那它是怎么利用动态代理来进行mapper xml与接口的连接呢?下面我将从源码成名说明一下整个流程,同时将会给一个简单的例子来说明它实现的原理。
先来看一段例子:
public class DynamicProxyTest {
static interface IHello {
public String sayHello();
}
static class DynaProxy implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("dynamic proxy");
return new String("123");
}
}
public static void main(String[] args) {
IHello hello = (IHello) Proxy.newProxyInstance(IHello.class.getClassLoader(), new Class[] { IHello.class }, new DynaProxy());
String str = hello.sayHello();
System.out.println(str);
}
}
请注意上面的例子,HelloImpl并未实现IHello,所以在DynaProxy中的invoke方法中不能调用method.invoke(Object obj, Object[] args),因为Java的动态代理机制要求obj上面的method调用的前提是obj实现了接口。此处虽然用了反射中的动态代理结构来组织代码实际上,此例子并非动态代理,这样就做到了IHello在没有任何实现的情况下,获得返回值。这主要就是MyBatis-3的mapper接口和xml的连接原理。
下面来翻一下MyBatis的源码,便于大家今后更方面的阅读。
MyBatis-3的使用,伪代码表示
String mapperResource = "mybatis-config.xml";
Reader reader = Resources.getResourceAsReader(mapperResource);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
session = sessionFactory.openSession();
AccountSecurityMasterMapper mapper = session.getMapper(AccountSecurityMasterMapper.class);
List<AccountSecurityMaster> result = mapper.selectAll();
mapper类
public interface AccountSecurityMasterMapper extends Mapper {
List<AccountSecurityMaster> selectAll();
}
关于此段代码的配置文件
<!-- mybatis-config.xml -->
<?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>
<typeAliases>
<typeAlias alias="AccountSecurityMaster" type="org.mark.domain.AccountSecurityMaster"/>
</typeAliases>
<mappers>
<mapper resource="org/mark/mapper/AccountSecurityMaster.xml"/>
</mappers>
</configuration>
<!-- AccountSecurityMaster.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="org.mark.mapper.AccountSecurityMasterMapper">
<cache />
<resultMap type="AccountSecurityMaster" id="AccountSecurityMasterResult">
<id column="ACCT_SEC_ID" property="acctSecId" />
<result column="FUND_ID" property="fundId" />
<result column="SECURITY_ID" property="securityId" />
</resultMap>
<select id="selectAll" parameterType="String"
resultMap="AccountSecurityMasterResult">
SELECT * FROM ACCOUNT_SECURITY_MASTER
</select>
</mapper>
DefaultSqlSession: SqlSession的子类,定义一些列的数据库操作。
XMLConfigBuilder : 读取mybatis-config.xml,并将xml中配置的内容映射成相应的java代码。
XMLMapperBuilder:读取AccountSecurityMaster.xml,并将其中的mapper的接口映射成MapperProxyFactory,并保存在MapperRegistry中。
Configuration:用来操作配置的一系列内容
MapperRegistry:处理与保持xml中Mapper对应的MapperProxyFactory。
MapperProxyFactory:创建mapper的接口的伪实例
MapperProxy:负责代理mapper的接口,并在invoke方法内返回MapperMethod的执行结果
MapperMethod:此类用于将AccountSecurityMaster.xml中的insert,update,delete,select配置直接映射成jdbc的statement操作。