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


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

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

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

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

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

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

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

    四、发现并解决问题
    回到自己的手写的mybatis源码中,自然就定位到了如下这个地方:

    对比一下mybatis的源码

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

  • 相关阅读:
    基于雪花算法的单机版
    Spring cloud gateway自定义filter以及负载均衡
    logback转义符与MDC
    录音地址文件保存
    maven加载本地jar
    ES Log4J配置信息
    java线程池
    openstreetmap的数据下载
    php更新版本后(路径更改后)要做的调整
    重启IIS
  • 原文地址:https://www.cnblogs.com/yanbincn/p/8779606.html
Copyright © 2020-2023  润新知