热爱学习,热爱生活!
沉淀、分享、成长,让自己和他人都有所收获!
我的介绍。
当我们使用Mybatis时,我们会遇到这样的问题:“为什么Mybatis只需要定义一个接口,并且可以使用XML或注释中的SQL语句来完成对数据库的CRUD,而不需要编写实现类?& # 8220;。在阅读了Mybatis的源代码后,我意识到Mybatis使用映射器
接口代理类将所有数据库操作移交给代理类。
二、绑定模块
这映射器
接口代理类在绑定模块,核心类是org.apache.ibatis.binding.映射器代理
。绑定
模块的核心类如下:
-
org.apach.ibatis.binding.映射器Registry
:映射器
接口注册类,管理映射器
接口类型及其代理创建工作的映射,这是我们在开发中创建的映射器
接口类将在这里注册以进行管理。 -
org.apach.ibatis.binding.映射器代理Factory
:映射器
接口代理类创建一个工厂类。 -
org.apach.ibatis.binding.映射器代理
:映射器
接口代理类,封装SqlSession
相关的运算,我们稍后会学到,是SQL
实现。 -
org.apach.ibatis.binding.映射器Method
:包映射器
接口和对应的方法SQL
执行信息,这是我们在开发过程中创建的映射器
接口类的每个方法对应于XML
配置SQL
声明。
流程图如下:
3.设计
通常,如果您能找到每个人正在做的事情的共同内容,并拥有统一的流程,那么它就可以被浓缩和细化,打包成公共组件或服务,并由每个人共享,以减少无用工作的重复。
参考我们最常用的JDBC
从获取数据库连接、查询、封装结果集到返回结果集的方法,这些步骤是固定的过程,因此我们可以将该过程封装到通用组件或服务中。
当我们设计一个蠕虫
在构建框架的过程中,首先要考虑如何集成用户自定义的数据库操作接口,XML
配置SQL
语句和数据库链接在一起。实际上,最合适的操作是使用代理方法进行处理,因为代理可以将一个复杂的流程封装为接口对象的实现类,设计如下:
- 首先提供一个
文件夹
接口代理类映射器Poxy
,通过代理类包装数据的操作。目前,我们将在本章中首先提供一个简单的包装器来模拟对数据库的调用。 - 然后
映射器
接口代理类提供了一个简单的工厂类映射器代理Factory
转移实例
每种方法映射器
接口成为代理类。
4、实现
在实现之前,我们首先学习了代理知识。我们使用动态代理模式。我们经过一个小的演示
要了解动态代理模式,还有另外两种代理模式:静态代理,格利布
表演。
动态代理
动态代理具有以下特点:
- 动态代理对象不需要实现接口,只有目标对象需要实现接口。
- 实现基于接口的动态代理需要使用
JDK
中性应用程序接口
,存在JVM
内存内动态构造代理
,在运行时有效。 -
需要使用
java.lang.reflect.代理
和它的new代理Instance ()
方法,此方法需要传入三个参数,源代码如下:@CallerSensitive public static Object new代理Instance(类加载器加载程序, Class<?>[] 接口, InvocationHandler h) throws IllegalArgumentException{ //... }
-
类加载器加载程序
:指定当前目标对象使用的类加载。获取加载器的方法为getClassLoader ()
。 -
接口
:目标对象实现接口类型,并使用泛型方法确认接口类型。 -
InvocationHandler h
:事件处理,当执行目标方法对象的方法时,将触发事件处理程序的方法,并将当前执行的目标对象的方法作为参数传入。
-
我们通过特定的实现在动态代理上执行操作。类结构图如下:
代码:
映射器
接口代理类:
public class 映射器代理<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private Map<String, String> sqlSession;
private final Class<T> mapperInterface;
public 映射器代理(Map<String, String> sqlSession, Class<T> mapperInterface) {
这.sqlSession = sqlSession;
这.mapperInterface = mapperInterface;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(方法。getDeclaringClass())) {
//The method in Object, execute directly
return 方法。invoke(这, args);
} else {
return "class" + mapperInterface.getName() + "is proxied, and the method is executed: " + 方法。getName() +
" , sqlSession is: " + sqlSession;
}
}
}
映射器
接口代理类创建一个工厂类:
public class 映射器代理Factory<T> {
/**
* 映射器 interface type
*/
private final Class<T> mapperInterface;
public 映射器代理Factory (Class<T> mapperInterface) {
这.mapperInterface = mapperInterface;
}
public T newInstance(Map<String, String> sqlSession) {
映射器代理 mapper代理 = new 映射器代理(sqlSession, mapperInterface);
return (T) 代理.new代理Instance(mapperInterface.getClassLoader (), new Class[]{mapperInterface}, mapper代理);
}
}
IUserDao
类型:
public interface IUserDao {
String queryUserName(String uId);
}
测试类:
public class 映射器代理Test {
@Test
public void test() {
映射器代理Factory<IUserDao> factory = new 映射器代理Factory<IUserDao>(IUserDao.class);
Map<String, String> sqlSession = new HashMap<>();
sqlSession.put("cn.bugstack.mybatis.test.dao.IUserDao.queryUserName", "Simulate the operation of executing the SQL statement in 映射器.xml: query user name");
sqlSession.put("cn.bugstack.mybatis.test.dao.IUserDao.queryUserAge", "Simulate the operation of executing the SQL statement in 映射器.xml: query user age");
IUserDao userDao = factory.newInstance(sqlSession);
String res = userDao.queryUserName("1");
System.out.println(res);
}
}
测试结果如下:
The class qtspace.cn.binding.IUserDao is proxied, and the method is executed: queryUserName, and the sqlSession is: {cn.bugstack.mybatis.test.dao.IUserDao.queryUserAge=Simulate the operation of executing the SQL statement in 映射器.xml: query user age , cn.bugstack.mybatis.test.dao.IUserDao.queryUserName=Simulate the operation of executing the SQL statement in 映射器.xml: query user name}
从以上测试结果可以看出IUserDao
已经被委派并正在执行映射器代理 #调用程序()
当代理执行该方法时IUserDao # queryUserName ()
方法。
必须注意的是:在动态代理的方式下,所有的方法都将通过调用程序()
方法执行,但动态代理的问题是它只能代理实现某个接口的实现类,而代理类只能代理接口中实现的方法。如果实现类有自己的私有方法,但不在接口中,则不能委派此方法。
