你好,我是田哥
前两天,一个朋友去面试,面试官问:说一下MyBatis动态代理原理?
主要还是他的简历上写了:深入研究过MyBatis源码
可是,这位朋友并没有看过,就只是背过一些八股文,面试者回答还是够优秀。
咱们不多说了,开始正题吧。
MyBatis是一个ORM工具,封装了JDBC的操作,简化业务编程。Mybatis在web工程中,与Spring集成,提供业务读写数据库的能力。
另外,市面上关于ORM框架很多,从我身边的朋友反馈来看,使用率:
MyBatis > MyBatis-Plus > JPA > Hibernate>其他
。
我们还是按照老规矩,从demo案例开始。
采用Maven包依赖管理,mybatis-3.5.5版本;同时需要数据库连接驱动
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
配置文件配置数据库连接源,及映射文件。
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<!-- 数据库连接方式 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/user" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<!-- 注册表映射文件 -->
<mappers>
<mapper resource="mybatis/User.xml"/>
</mappers>
</configuration>
定义实体:
@Data
public class User {
private String username;
private String password;
}
接口定义
public interface UserMapper {
List<User> queryUser();
}
定义映射文件
<?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.xiongxin.mybatis.mapper.UserMapper">
<select id="queryUser" resultType="com.xiongxin.mybatis.entity.User">
select * from tbl_user
</select>
</mapper>
public class TestMain {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
//加载 mybatis 的配置文件(它也加载关联的映射文件)
Reader reader = Resources.getResourceAsReader(resource);
//构建 sqlSession 的工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建能执行映射文件中 sql 的 sqlSession
SqlSession session = sessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> users = userMapper.queryUser();
System.out.println(JSON.toJSONString(users));
}
}
---------------------------------
..consule print..
[{"password":"password","username":"xiongxin"}]
到这里,这个Mybatis的使用环节结束。
整个实现过程中,我们并未编写Mapper的实现类,框架是如何在无实现类的场景下实现接口方法返回的呢?
这里就不得不说到接口的动态代理方法了。
请看下面这张图:
层次结构
SqlSession接口的实现中,获取Mapper的代理实现类
使用了JDK动态代理的功能
代理类执行方法调用
方法调用中执行MethodInvoker
最终执行execue方法。
获取返回结果Result。
我对MyBatis进行了深入的研究,以及形成文档形式,请看下面这个思维导图: