探索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()生成的代理类解析的主要内容,如果未能解决你的问题,请参考以下文章