探索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的操作。

如果上面的main方法配置行不通,还有一种是通过配置JVM参数 -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 来把JDK生成的代理类持久化到本地。

 

 

posted @ 2019-07-22 23:36  賣贾笔的小男孩  阅读(1448)  评论(0编辑  收藏  举报