关于mybatis的mapper接口是如何实现的,下面有两个小案例帮助理解。
1.关于jdk的动态代理
JAVA实现动态代理的两种方式…
本以为JDK的动态代理只能代理接口的实现类,今天才发现它可以直接代理接口,并通过Proxy类来生成接口的代理对象,原谅我个小白。
实验一下:
首先创建了一个接口类TestObject,定义了一个抽象方法sayHello。
public interface TestObject {
public String sayHello(String name);
}
创建了一个主类,通过Proxy去生成TestObject接口的代理对象res,这里使用匿名内部类的方式创建了InvocationHandler接口的对象,并实现了invoke方法,在这个方法里我们可以代理对象、目标对象的方法对象、目标对象的方法参数等信息,方法内部我们返回了一个字符串。
然后获取到代理对象res,并调用sayHello方法传入参数“liaopeng”,结果输出了”hello liaopeng“,表示成功了。
public class Test {
public static void main(String[] args){
TestObject res = (TestObject) Proxy.newProxyInstance(TestObject.class.getClassLoader(),
new Class[]{TestObject.class},
(Object proxy, Method method, Object[] params)->{
return "hello "+params[0].toString();
});
System.out.println(res.sayHello("liaopeng"));
}
}
运行结果:
2. mybatis的mapper接口的实现原理
在mybatis中我们可以通过调用mapper接口去直接获取数据库中的数据,而不需要去实现mapper接口,其实是就是使用了动态代理的方式,为mapper接口创建了代理对象,在代理对象中实现了相应的访问数据库的逻辑。
示例:
这里定义了一个接口包含两个抽象方法sayHello和sayAge。
public interface TestObject {
public String sayHello(String name);
public int sayAge(int age);
}
这里大致和上一个示例差不多,只是匿名内部类的实现方法不同。这里根据不同的方法名称实现了不同逻辑,其实就是对接口类的实现。
我们知道mybatis中是通过namespace+id的方式来唯一确定一条mapper.xml中配置的Sql语句。而mybatis有两种方式执行sql访问数据库,第一种是mapper接口的方式,第二种是通过调用sqlSession的方法传入一条sql的定位和参数去访问,如:sqlSession.selectOne("com.test.mapper.UserMapper.getUserById",1);
其实mapper接口的方式,底层就是通过动态代理的方式生成代理对象,对接口方法进行实现。而这里的实现就是使用以上的第二种方式进行实现,例如,以上的selectOne方法的第一个参数就是接口的全限类名+方法名,第二个参数就是传入接口方法的参数。
以下只是一个示例,帮助理解,详情参见源码。
public class Test {
public static void main(String[] args){
TestObject res = (TestObject) Proxy.newProxyInstance(TestObject.class.getClassLoader(),
new Class[]{TestObject.class},
(proxy, method, params)->{
System.out.println("method: "+method.getName());
System.out.println("method resultType: "+method.getReturnType());
System.out.println("method parametersType: "+method.getGenericReturnType());
System.out.println("method parametersCount: "+method.getParameterCount());
switch (method.getName()){
case "sayHello":
return "hello "+params[0].toString();
case "sayAge":
return params[0];
}
return null;
});
System.out.println(res.sayHello("liaopeng"));
System.out.println();
System.out.println(res.sayAge(18));
}
}
运行结果: