• 探索Mybatis之JDK动态代理:探究Proxy.newProxyInstance()生成的代理类解析


    Mybatis的Mapper接口UserMapper

     1 package com.safin.Mapper;
     2 
     3 import com.safin.Pojo.User;
     4 
     5 import java.util.List;
     6 
     7 public interface UserMapper {
     8     int insertUser(User user);
     9     User getUser(Long id);
    10     List<User> findUser(String userName);
    11 }

    我使用的jdk版本是12的,在java.lang.reflect包下的ProxyGenerator是生成代理类的工具,这是用来生成运行时代理类($proxy为前缀)。注意其中一个属性,这是用来保存那些构建的代理类的开关saveGeneratedFiles,其默认赋值是false,当saveGeneratedFiles的值为true时,那些运行时生成的代理类将会以.class文件保存下来。

    1 /** debugging flag for saving generated class files */
    2     private static final boolean saveGeneratedFiles =
    3         java.security.AccessController.doPrivileged(
    4             new GetBooleanAction(
    5                 "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();

    在测试主函数开始第一句先添加如下代码,把saveGeneratedFiles的开关打开。jdk12中的"jdk.proxy.ProxyGenerator.saveGeneratedFiles"这个值与jdk8中的稍微不同,在jdk8的这个值是"sun.misc.ProxyGenerator.saveGeneratedFiles"。说起misc,他的全称应该是minimal instruction set computer,最小指令集计算机是一种处理器体系结构,具有非常少量的基本操作和相应的操作码。

    还有jdk8与jdk12的Proxy的实现发生了很大的变化,以后有时间再去研究研究。

    1 System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

    测试的Main函数如下:

     1 public static void main(String[] args) throws IOException {
     2         SqlSession sqlSession = null;
     3         System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true"); // 打开保存生成的代理类
     4 
     5         try {
     6             sqlSession = SqlSessionFactoryUtil.openSqlSession();
     7             UserMapper userMapper = (UserMapper)sqlSession.getMapper(UserMapper.class);
     8             User user = null;
     9             user = userMapper.getUser(30L);
    10             sqlSession.commit();
    11         } catch (Exception var9) {
    12             System.err.println(var9.getMessage());
    13             sqlSession.rollback();
    14         } finally {
    15             if (sqlSession != null) {
    16                 sqlSession.close();
    17             }
    18 
    19         }
    20 
    21     }

    运行后保存了许多代理类,找出与Mapper有关的的代理类$proxy,代理类经过IDEA的反编译后,代码如下:

      1 //
      2 // Source code recreated from a .class file by IntelliJ IDEA
      3 // (powered by Fernflower decompiler)
      4 //
      5 
      6 package com.sun.proxy;
      7 
      8 import com.safin.Mapper.UserMapper;
      9 import com.safin.Pojo.User;
     10 import java.lang.reflect.InvocationHandler;
     11 import java.lang.reflect.Method;
     12 import java.lang.reflect.Proxy;
     13 import java.lang.reflect.UndeclaredThrowableException;
     14 import java.util.List;
     15 
     16 public final class $Proxy19 extends Proxy implements UserMapper {
     17     private static Method m1;
     18     private static Method m3;
     19     private static Method m4;
     20     private static Method m5;
     21     private static Method m2;
     22     private static Method m0;
     23    
     24     public $Proxy19(InvocationHandler var1) throws  {
     25         super(var1);   // 传入构造方法的参数是实现了InvocationHandler接口的MapperProxy
     26     }
     27 
     28     public final boolean equals(Object var1) throws  {
     29         try {
     30             return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); // 从InvocationHandler的invoke方法
     31         } catch (RuntimeException | Error var3) {
     32             throw var3;
     33         } catch (Throwable var4) {
     34             throw new UndeclaredThrowableException(var4);
     35         }
     36     }
     37 
     38     public final User getUser(Long var1) throws  {
     39         try {
     40             return (User)super.h.invoke(this, m3, new Object[]{var1});
     41         } catch (RuntimeException | Error var3) {
     42             throw var3;
     43         } catch (Throwable var4) {
     44             throw new UndeclaredThrowableException(var4);
     45         }
     46     }
     47 
     48     public final int insertUser(User var1) throws  {
     49         try {
     50             return (Integer)super.h.invoke(this, m4, new Object[]{var1});
     51         } catch (RuntimeException | Error var3) {
     52             throw var3;
     53         } catch (Throwable var4) {
     54             throw new UndeclaredThrowableException(var4);
     55         }
     56     }
     57 
     58     public final List findUser(String var1) throws  {
     59         try {
     60             return (List)super.h.invoke(this, m5, new Object[]{var1});
     61         } catch (RuntimeException | Error var3) {
     62             throw var3;
     63         } catch (Throwable var4) {
     64             throw new UndeclaredThrowableException(var4);
     65         }
     66     }
     67 
     68     public final String toString() throws  {
     69         try {
     70             return (String)super.h.invoke(this, m2, (Object[])null);
     71         } catch (RuntimeException | Error var2) {
     72             throw var2;
     73         } catch (Throwable var3) {
     74             throw new UndeclaredThrowableException(var3);
     75         }
     76     }
     77 
     78     public final int hashCode() throws  {
     79         try {
     80             return (Integer)super.h.invoke(this, m0, (Object[])null);
     81         } catch (RuntimeException | Error var2) {
     82             throw var2;
     83         } catch (Throwable var3) {
     84             throw new UndeclaredThrowableException(var3);
     85         }
     86     }
     87 
     88     static { // 拿到了反射API的Method
     89         try {
     90             m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
     91             m3 = Class.forName("com.safin.Mapper.UserMapper").getMethod("getUser", Class.forName("java.lang.Long"));
     92             m4 = Class.forName("com.safin.Mapper.UserMapper").getMethod("insertUser", Class.forName("com.safin.Pojo.User"));
     93             m5 = Class.forName("com.safin.Mapper.UserMapper").getMethod("findUser", Class.forName("java.lang.String"));
     94             m2 = Class.forName("java.lang.Object").getMethod("toString");
     95             m0 = Class.forName("java.lang.Object").getMethod("hashCode");
     96         } catch (NoSuchMethodException var2) {
     97             throw new NoSuchMethodError(var2.getMessage());
     98         } catch (ClassNotFoundException var3) {
     99             throw new NoClassDefFoundError(var3.getMessage());
    100         }
    101     }
    102 }

    可以看见生成的代理类 $Proxy19 继承了 Proxy 类,实现了Mybatis的 UserMapper 接口,调用InvocationHandler的invoke方法来利用MapperMethod来对sqlSession的操作。

     

  • 相关阅读:
    Protocol https not supported or disabled in libcurl
    初学require.js
    HTML中的IE条件注释
    前端,我为什么不要你
    敲点JavaScript代码
    小白科普之JavaScript的函数
    小白科普之JavaScript的BOM模型
    小白科普之JavaScript的JSON
    小白科普之JavaScript的数组
    document.documentElement和document.body的区别
  • 原文地址:https://www.cnblogs.com/magic-sea/p/11229237.html
Copyright © 2020-2023  润新知