JDK代理,代理的是接口,那么笔者想一想,既然代理的是接口,那如果没有实现类怎么办,能不能代理。答案是可以的,Mybatis就是这样的。
Mybatis使用JDK动态代理来实现Mapper接口,事先保存好Mapper接口,和接口声明的方法,返回值,参数类型,然后代理类的方法调用的时候使用MapperMethod这个事先放入方法缓存里的对象来真实调用功能。
笔者极度简化了一下代码:
被代理的接口:
public interface Subject2 {
String selectById();
}
这个接口可以看成是Mapper接口
代理对象:
public class SubjectProxy2<T> implements InvocationHandler {
private Class<T> proxyInterface;
//这里可以维护一个缓存,存这个接口的方法抽象的对象
SubjectProxy2(Class<T> proxyInterface){
this.proxyInterface = proxyInterface;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("selectById")){
//String result = (String) method.invoke(proxyInterface,args);
//这里可以得到方法抽象对象来调用真的的查询方法
System.out.println("selectById调用成功");
}
return null;
}
public T getProxy(){
return (T) Proxy.newProxyInstance(proxyInterface.getClassLoader(),new Class[]{proxyInterface},this);
}
}
这个代理类使用了泛型,说明这个代理类可以代理所有的mapper接口。
那么接下来测试一下:
public class ProxyTest2 {
public static void main(String[] args) {
SubjectProxy2<Subject2> subjectProxy2 = new SubjectProxy2(Subject2.class);
Subject2 subject2 = subjectProxy2.getProxy();
subject2.selectById();
}
}
结果不言而喻。肯定会有相应的输出
没有看mybatis源码的时候,我以为动态代理一定要要有实现类才能代理,但是看了优秀的顶级大牛的源码之后,我才发现,原来还可以这样。