从Mybatis源码理解jdk动态代理默认调用invoke方法

1、背景
最近在工做之余,把mybatis的源码看了下,决定本身手写个简单版的。实现核心的功能便可。写完以后,执行了一下,正巧在mybatis对Mapper接口的动态代理这个核心代码这边发现一个问题。正好再回头看下jdk的动态代理,才发现问题所在。mybatis

2、问题
当我用SqlSession.getMapper() 方法来获取Mapper的代理类的时候,发现这个代理对象所展现的toString()是个null。以下图app

而debug了一下mybatis的源码,发现是有值,而且的确是new 代理的目标对象为MapperProxy类型spa

3、回头看jdk动态代理
当我在排查问题的时候,无心中发现,在执行(T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);方法时,居然会抛出 mapperProxy类的invoke方法中的异常,可是这个时候程序尚未走到任何代理的方法。
回头找了下以前学着写的动态代理的例子,并在invoke方法里面输出了method。以下:debug

启动main方法,发现打印的内容:3d

这时候才发现,在实例化代理类的时候,会调用一次invoke()方法,而且此时调用方法的method参数是Object.toString() 。看到这发现了两点代理

  1. invoke方法在实例化代理的时候会调用一次,若是这个方法有对全局的公共变量作修改的话,会存在隐患的问题
  2. 代理类的toString 最后出来的类的名称就是调用这个方法获得的。将代码中result输出就是对应的代理类。

4、发现并解决问题
回到本身的手写的mybatis源码中,天然就定位到了以下这个地方:对象

对比一下mybatis的源码blog

 

正是红框中的代码,本身手写的时候认为代理的方法的声明类都是定义的mapper接口,这边的判断其实没有必要,也走不到。然而从第三点中能够知道,在new 代理类的时候传入的Method为toString方法正好进了这个分支,而且调用了当前MapperProxy实例的toString方法,返回了代理类的名称,正是以前所缺失的。把这段代码加上就OK了接口

相关文章
相关标签/搜索