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

Posted magic-sea

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了探索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的操作。

 

 

以上是关于探索Mybatis之JDK动态代理:探究Proxy.newProxyInstance()生成的代理类解析的主要内容,如果未能解决你的问题,请参考以下文章

动态代理之JDK Proxy浅析

AOP之JDK动态代理和CGLib动态代理

设计模式三: 代理模式(Proxy) -- JDK的实现方式

Mybatis之jdk动态代理和cglib动态代理

Mybatis之jdk动态代理和cglib动态代理

Mybatis之jdk动态代理和cglib动态代理