打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
从mybatis源码看JDK动态代理

网上好多说到动态代理的文章内容都是这样子的:

一个实际干事的类Real;一个被创造的代理类Proxy。

Proxy调用Real中被代理的方法;有模有样的在被代理的方法前后打印出一些字符串。

比如下面的例子:

 1 public class JdkProxy { 2     static interface IProxy{ 3         String say(String s); 4     } 5     static class Real implements IProxy{ 6         @Override 7         public String say(String s) { 8             System.out.println("说完了,返回结果"); 9             return s;10         }11     }   12 13     static class MyInvocationHandler implements  InvocationHandler{14         private Object real;15 16         public MyInvocationHandler(Object real) {17             this.real = real;18         }19 20         @Override21         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {22             Object res=null;23             if(method.getName().equals("say")){24                 System.out.println("say start...");25                 res=method.invoke(real,args);26                 System.out.println("say end...");27             }28             return res;29         }30     }    31 32     public static void main(String[] args) {33         execu1();      34     }35 36     private static void execu1(){37         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");38         Real real=new Real();39         IProxy proxy=(IProxy) Proxy.newProxyInstance(real.getClass().getClassLoader(), real.getClass().getInterfaces(),new MyInvocationHandler(real));40         String s=proxy.say("abc");41         System.out.println(s);42     }   43 44 }

上面21-27行代码是调用被代理的方法;

如果我现在不调用被代理的方法,而是直接写一个方法体。

代码如下:

 1 public class JdkProxy { 2     static interface IProxy{ 3         String say(String s); 4     } 5     static class Real implements IProxy{ 6         @Override 7         public String say(String s) { 8             System.out.println("说完了,返回结果"); 9             return s;10         }11     }   12 13     static class MyInvocationHandler implements  InvocationHandler{14         private Object real;15 16         public MyInvocationHandler(Object real) {17             this.real = real;18         }19 20         @Override21         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {22            return "我什么也不代理,我直接就是一个方法";23         }24     }    25 26     public static void main(String[] args) {27         execu1();      28     }29 30     private static void execu1(){31         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");32         Real real=new Real();33         IProxy proxy=(IProxy) Proxy.newProxyInstance(IProxy.class.getClassLoader(),new Class[]{IProxy.class},new MyInvocationHandler(real));34         String s=proxy.say("abc");35         System.out.println(s);36     }   37 38 }

改动代码是22行的代码。

如果不需要被代理的方法了,那么还需要实际干活的类吗?

继续修改代码:

 1 public class JdkProxy { 2     static interface IProxy{ 3         String say(String s); 4     }    5  6     static class MyInvocationHandler implements  InvocationHandler{ 7          8  9         @Override10         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {11            return "我什么也不代理,我直接就是一个方法";12         }13     }    14 15     public static void main(String[] args) {16         execu1();      17     }18 19     private static void execu1(){20         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");      21         IProxy proxy=(IProxy) Proxy.newProxyInstance(IProxy.class.getClassLoader(),new Class[]{IProxy.class},new MyInvocationHandler());22         String s=proxy.say("abc");23         System.out.println(s);24     } 25 }

 上面的程序依然能够正常运行。

从这个层面来说,动态代理就是给我们创造了一个类,至于有没有实际干活的类无关。

网上到处都在说mybatis接口编程的用的是动态代理,创造代理类我们很好理解,那么他到底代理了什么类呢?

先来个简单的mybatis例子:

1 SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));2 SqlSession sqlSession= sqlSessionFactory.openSession();3 IRoleMapper iRoleMapper=sqlSession.getMapper(IRoleMapper.class);4 List<Role> list=iRoleMapper.getRole(1L);

第三行代码就应该是获取代理的过程;iRoleMapper指向具体的代理类。

下面查看源码:

getMapper()源码:

 1  public <T> T getMapper(Class<T> type, SqlSession sqlSession) { 2     final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); 3     if (mapperProxyFactory == null) { 4       throw new BindingException("Type " + type + " is not known to the MapperRegistry."); 5     } 6     try { 7       return mapperProxyFactory.newInstance(sqlSession); 8     } catch (Exception e) { 9       throw new BindingException("Error getting mapper instance. Cause: " + e, e);10     }11   }

代码比较简洁,代理类是在第7行生成的。进入newInstance()方法:

newInstance()源码:

1 protected T newInstance(MapperProxy<T> mapperProxy) {2     return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);3   }4 5   public T newInstance(SqlSession sqlSession) {6     final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);7     return newInstance(mapperProxy);8   }

第1行的newInstance调用的是JDK的代理方法

第5行的newInstance是Mybatis自己的方法,根据JDK动态代理的调用规则,第6行的MapperProxy一定继承了InvocationHandler接口,并且实现了接口方法invoke();

invoke()源码

 1  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 2     try { 3       if (Object.class.equals(method.getDeclaringClass())) { 4         return method.invoke(this, args); 5       } else if (method.isDefault()) { 6         if (privateLookupInMethod == null) { 7           return invokeDefaultMethodJava8(proxy, method, args); 8         } else { 9           return invokeDefaultMethodJava9(proxy, method, args);10         }11       }12     } catch (Throwable t) {13       throw ExceptionUtil.unwrapThrowable(t);14     }15     final MapperMethod mapperMethod = cachedMapperMethod(method);16     return mapperMethod.execute(sqlSession, args);17   }

invoke()方法体中并没有调用    res=method.invoke(real,args);这类的代码。说明一个问题,这里并没有我们常说的Real这样的类。

总结:

1.JDK动态代理只是需要一个接口,至于实际干活类不是必须的;至于具体做什么,由程序员在invoke()中去实现。

2.Mybatis用了JDK动态代理,但是并没有提供被代理的类;只是提供了一个代理类或者干脆说提供了一个我们看不见的类用于执行Sql

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
设计模式--代理模式 - 设计模式
jdk动态代理使用实例详解
动态代理
java动态代理 AOP封装 张孝祥
深入浅出Mybatis
动态代理在 Retrofit 中的使用
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服