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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM