java動態代理源碼解析


眾所周知,java動態代理同反射原理一直是許多框架的底層實現,之前一直沒有時間來分析動態代理的底層源碼,現結合源碼分析一下動態代理的底層實現

類和接口

java動態代理的主要類和接口有:java.lang.reflect.Proxy、java.lang.reflect.InvocationHandler

1 java.lang.reflect.Proxy:動態代理機制的主類,提供一組靜態方法為一組接口動態的生成對象和代理類。

1、public static InvocationHandler getInvocationHandler(Object var0) -> 該方法用於獲取指定代理對象所關聯的調用處理器

2、public static Class<?> getProxyClass(ClassLoader var0, Class... var1) -> 該方法用於獲取關聯於指定類裝載器和一組接口的動態代理類的類對象

3、public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2) ->方法用於為指定類裝載器、一組接口及調用處理器生成動態代理類實例

 

2  java.lang.reflect.InvocationHandler:調用處理器接口,自定義invoke方法,用於實現對於真正委托類的代理訪問

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

3  java.lang.ClassLoader:類裝載器類

 將類的字節碼裝載到 Java 虛擬機(JVM)中並為其定義類對象,然后該類才能被使用。Proxy類與普通類的唯一區別就是其字節碼是由 JVM 在運行時動態生成的而非預存在於任何一個 .class 文件中。

 demo

public interface HelloService {
    void sayHello();
}
定義接口
public class HelloServiceImpl implements HelloService{
    @Override
    public void sayHello() {
        System.out.println("hello 張三");
    }
}
接口實現
public class HelloServiceProxy implements InvocationHandler{
    private Object target;

    public Object bind(Object target, Class[] interfaces) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result;
        System.out.println("###########這里是動態代理##########");
        //反射方法前調用
        System.out.println("調用前");
        //反射執行方法  相當於調用target.sayHelllo;
        result = method.invoke(target,args);
        //反射方法后調用.
        System.out.println("調用后");

        return result;
    }
}
生成代理類
public class ProxyTest {

    public static void main(String[] args) {
        HelloServiceProxy proxy = new HelloServiceProxy();
        HelloService service = new HelloServiceImpl();
        HelloService serviceProxy = (HelloService)proxy.bind(service, new Class[] {HelloService.class});

        serviceProxy.sayHello();
    }
}
測試類

運行結果:

 源碼分析:

1 Proxy類的靜態方法newProxyInstance方法

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        //驗證傳入的InvocationHandler是否為空
        Objects.requireNonNull(h);
        
        //克隆代理類實現的接口
        final Class<?>[] intfs = interfaces.clone();
        //獲得安全管理器
        final SecurityManager sm = System.getSecurityManager();
        //檢查創建代理類所需的權限
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         * 查找或者生成特定的代理類(如果緩存中存在,則直接獲取)
         */
    
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            //權限校驗
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //獲取參數類型是InvocationHandler.class的代理類構造器
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //如果代理類是不可訪問的, 就使用特權將它的構造器設置為可訪問
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //傳入InvocationHandler實例去構造一個代理類的實例,所有代理類都繼承自Proxy,而Proxy構造方法需要InvocationHandler實例作為參數
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }
newProxyInstance

  從newProxyInstance方法看出,產生代理類核心代碼在getProxyClass0

2 Proxy類的靜態方法getProxyClass0方法

 1     private static Class<?> getProxyClass0(ClassLoader loader,
 2                                            Class<?>... interfaces) {
 3         if (interfaces.length > 65535) {
 4             throw new IllegalArgumentException("interface limit exceeded");
 5         }
 6 
 7         // If the proxy class defined by the given loader implementing
 8         // the given interfaces exists, this will simply return the cached copy;
 9         // otherwise, it will create the proxy class via the ProxyClassFactory
10         //如果由實現給定接口的代理類存在,這將簡單地返回緩存的副本;否則,將通過ProxyClassFactory創建代理類
11         return proxyClassCache.get(loader, interfaces);
12     }
getProxyClass0

getProxyClass0通過類加載器和接口集合去緩存里面獲取,如果能找到代理類就直接返回,否則就會調用ProxyClassFactory這個工廠去生成一個代理類,下面我們看下Proxy的靜態內部類ProxyClassFactory

3 ProxyClassFactory

  1 private static final class ProxyClassFactory
  2         implements BiFunction<ClassLoader, Class<?>[], Class<?>>
  3     {
  4         // prefix for all proxy class names 代理類名稱前綴
  5         private static final String proxyClassNamePrefix = "$Proxy";
  6 
  7         // next number to use for generation of unique proxy class names, 用原子類來生成代理類的序號, 保證序號唯一
  8         private static final AtomicLong nextUniqueNumber = new AtomicLong();
  9 
 10         @Override
 11         public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
 12 
 13             Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
 14             for (Class<?> intf : interfaces) {
 15                 /*
 16                  * Verify that the class loader resolves the name of this
 17                  * interface to the same Class object.
 18                  */
 19                 Class<?> interfaceClass = null;
 20                 try {
 21                     interfaceClass = Class.forName(intf.getName(), false, loader);
 22                 } catch (ClassNotFoundException e) {
 23                 }
 24                 //intf是否可以由指定的類加載進行加載
 25                 if (interfaceClass != intf) {
 26                     throw new IllegalArgumentException(
 27                         intf + " is not visible from class loader");
 28                 }
 29                 /*
 30                  * Verify that the Class object actually represents an
 31                  * interface.
 32                  * intf是否是一個接口
 33                  */
 34                 if (!interfaceClass.isInterface()) {
 35                     throw new IllegalArgumentException(
 36                         interfaceClass.getName() + " is not an interface");
 37                 }
 38                 /*
 39                  * Verify that this interface is not a duplicate.
 40                  * intf在數組中是否有重復
 41                  */
 42                 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
 43                     throw new IllegalArgumentException(
 44                         "repeated interface: " + interfaceClass.getName());
 45                 }
 46             }
 47             // package to define proxy class in 生成代理類的包名
 48             String proxyPkg = null;
 49             // 代理類的訪問標志, 默認是public final
 50             int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
 51 
 52             /*
 53              * Record the package of a non-public proxy interface so that the
 54              * proxy class will be defined in the same package.  Verify that
 55              * all non-public proxy interfaces are in the same package.
 56              * 驗證所有非公共代理接口都在同一個包中
 57              */
 58             for (Class<?> intf : interfaces) {
 59                 //獲取接口的訪問標志
 60                 int flags = intf.getModifiers();
 61                 //如果接口的訪問標志不是public, 那么生成代理類的包名和接口包名相同
 62                 if (!Modifier.isPublic(flags)) {
 63                     //生成的代理類的訪問標志設置改為final
 64                     accessFlags = Modifier.FINAL;
 65                     String name = intf.getName();
 66                     int n = name.lastIndexOf('.');
 67                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
 68                     if (proxyPkg == null) {
 69                         proxyPkg = pkg;
 70                     } else if (!pkg.equals(proxyPkg)) {
 71                         //代理類如果實現不同包的接口, 並且接口都不是public的, 那么就會在這里報錯
 72                         throw new IllegalArgumentException(
 73                             "non-public interfaces from different packages");
 74                     }
 75                 }
 76             }
 77 
 78             if (proxyPkg == null) {
 79                 // if no non-public proxy interfaces, use com.sun.proxy package 如果沒有非公共代理接口,那生成的代理類都放到默認的包下:com.sun.proxy
 80                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
 81             }
 82 
 83             /*
 84              * Choose a name for the proxy class to generate.
 85              * 生成代理類的全限定名, 包名+前綴+序號, 例如:com.sun.proxy.$Proxy0
 86              */
 87             long num = nextUniqueNumber.getAndIncrement();
 88             String proxyName = proxyPkg + proxyClassNamePrefix + num;
 89 
 90             /*
 91              * Generate the specified proxy class.
 92              * 這里是核心, 用ProxyGenerator來生成字節碼, 該類放在sun.misc包下
 93              */
 94             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
 95                 proxyName, interfaces, accessFlags);
 96             //根據二進制文件生成相應的Class實例
 97             try {
 98                 return defineClass0(loader, proxyName,
 99                                     proxyClassFile, 0, proxyClassFile.length);
100             } catch (ClassFormatError e) {
101                 /*
102                  * A ClassFormatError here means that (barring bugs in the
103                  * proxy class generation code) there was some other
104                  * invalid aspect of the arguments supplied to the proxy
105                  * class creation (such as virtual machine limitations
106                  * exceeded).
107                  */
108                 throw new IllegalArgumentException(e.toString());
109             }
110         }
111     }
ProxyClassFactory

ProxyClassFactory中生成代理類核心代碼 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);下面我們繼續分析ProxyGenerator.generateProxyClass

4 ProxyGenerator.generateProxyClass

 1 public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
 2         //構造ProxyGenerator對象
 3         ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
 4         //核心代碼,生成代理類字節碼文件
 5         final byte[] var4 = var3.generateClassFile();
 6         //如果需要保存生成的字節碼文件,則將字節碼文件寫入磁盤
 7         if(saveGeneratedFiles) {
 8             AccessController.doPrivileged(new PrivilegedAction() {
 9                 public Void run() {
10                     try {
11                         int var1 = var0.lastIndexOf(46);
12                         Path var2;
13                         //生成存儲路徑
14                         if(var1 > 0) {
15                             Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar), new String[0]);
16                             Files.createDirectories(var3, new FileAttribute[0]);
17                             var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
18                         } else {
19                             var2 = Paths.get(var0 + ".class", new String[0]);
20                         }
21                         //將字節碼文件寫入磁盤
22                         Files.write(var2, var4, new OpenOption[0]);
23                         return null;
24                     } catch (IOException var4x) {
25                         throw new InternalError("I/O exception saving generated file: " + var4x);
26                     }
27                 }
28             });
29         }
30         //返回字節碼文件
31         return var4;
32     }
generateProxyClass

ProxyGenerator.generateClassFile

跟蹤了這么久源碼,大boss終於出現了,下面我們分析ProxyGenerator.generateClassFile方法

  1     private byte[] generateClassFile() {
  2         //1、將所有的方法組裝成ProxyMethod對象
  3         //首先為代理類生成toString, hashCode, equals等代理方法
  4         this.addProxyMethod(hashCodeMethod, Object.class);
  5         this.addProxyMethod(equalsMethod, Object.class);
  6         this.addProxyMethod(toStringMethod, Object.class);
  7         Class[] var1 = this.interfaces;
  8         int var2 = var1.length;
  9 
 10         int var3;
 11         Class var4;
 12         //遍歷每一個接口的每一個方法, 並生成ProxyMethod對象
 13         for(var3 = 0; var3 < var2; ++var3) {
 14             var4 = var1[var3];
 15             Method[] var5 = var4.getMethods();
 16             int var6 = var5.length;
 17 
 18             for(int var7 = 0; var7 < var6; ++var7) {
 19                 Method var8 = var5[var7];
 20                 this.addProxyMethod(var8, var4);
 21             }
 22         }
 23 
 24         Iterator var11 = this.proxyMethods.values().iterator();
 25 
 26         List var12;
 27         while(var11.hasNext()) {
 28             var12 = (List)var11.next();
 29             checkReturnTypes(var12);
 30         }
 31 
 32         //2、組裝要生成的class文件的所有的字段信息和方法信息
 33         Iterator var15;
 34         try {
 35             //添加構造器方法
 36             this.methods.add(this.generateConstructor());
 37             var11 = this.proxyMethods.values().iterator();
 38 
 39             //遍歷緩存中的代理方法
 40             while(var11.hasNext()) {
 41                 var12 = (List)var11.next();
 42                 var15 = var12.iterator();
 43 
 44                 while(var15.hasNext()) {
 45                     ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
 46                     //添加代理類的靜態字段, 例如:private static Method m1;
 47                     this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
 48                     //添加代理類的代理方法
 49                     this.methods.add(var16.generateMethod());
 50                 }
 51             }
 52 
 53             //添加代理類的靜態字段初始化方法
 54             this.methods.add(this.generateStaticInitializer());
 55         } catch (IOException var10) {
 56             throw new InternalError("unexpected I/O Exception", var10);
 57         }
 58 
 59         if(this.methods.size() > '\uffff') {
 60             throw new IllegalArgumentException("method limit exceeded");
 61         } else if(this.fields.size() > '\uffff') {
 62             throw new IllegalArgumentException("field limit exceeded");
 63         } else {
 64             //3、寫入最終的class文件
 65             //驗證常量池中存在代理類的全限定名
 66             this.cp.getClass(dotToSlash(this.className));
 67             //驗證常量池中存在代理類父類的全限定名
 68             this.cp.getClass("java/lang/reflect/Proxy");
 69             var1 = this.interfaces;
 70             var2 = var1.length;
 71 
 72             //驗證常量池存在代理類接口的全限定名
 73             for(var3 = 0; var3 < var2; ++var3) {
 74                 var4 = var1[var3];
 75                 this.cp.getClass(dotToSlash(var4.getName()));
 76             }
 77 
 78             //接下來要開始寫入文件了,設置常量池只讀
 79             this.cp.setReadOnly();
 80             ByteArrayOutputStream var13 = new ByteArrayOutputStream();
 81             DataOutputStream var14 = new DataOutputStream(var13);
 82 
 83             try {
 84                 //1.寫入魔數
 85                 var14.writeInt(-889275714);
 86                 //2.寫入次版本號
 87                 var14.writeShort(0);
 88                 //3.寫入主版本號
 89                 var14.writeShort(49);
 90                 //4.寫入常量池
 91                 this.cp.write(var14);
 92                 //5.寫入訪問修飾符
 93                 var14.writeShort(this.accessFlags);
 94                 //6.寫入類索引
 95                 var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
 96                 //7.寫入父類索引, 生成的代理類都繼承自Proxy
 97                 var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
 98                 //8.寫入接口計數值
 99                 var14.writeShort(this.interfaces.length);
100                 
101                 Class[] var17 = this.interfaces;
102                 int var18 = var17.length;
103 
104                 //9.寫入接口集合
105                 for(int var19 = 0; var19 < var18; ++var19) {
106                     Class var22 = var17[var19];
107                     var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
108                 }
109                 //10.寫入字段計數值
110                 var14.writeShort(this.fields.size());
111                 var15 = this.fields.iterator();
112                 //11.寫入字段集合 
113                 while(var15.hasNext()) {
114                     ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
115                     var20.write(var14);
116                 }
117                 //12.寫入方法計數值
118                 var14.writeShort(this.methods.size());
119                 var15 = this.methods.iterator();
120                 //13.寫入方法集合
121                 while(var15.hasNext()) {
122                     ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
123                     var21.write(var14);
124                 }
125                  //14.寫入屬性計數值, 代理類class文件沒有屬性所以為0
126                 var14.writeShort(0);
127                 //轉換成二進制數組輸出
128                 return var13.toByteArray();
129             } catch (IOException var9) {
130                 throw new InternalError("unexpected I/O Exception", var9);
131             }
132         }
133     }
generateClassFile

動態代理的本質:通過類加載器獲取類字節碼,通過類實現的接口反射獲得該類的屬性,方法等,並生成新的字節碼文件

6 代理類字節碼文件分析 $Proxy0.class

  1 package com.sun.proxy;
  2 
  3 import com.doubibi.framework.util.proxy.HelloService;
  4 import java.lang.reflect.InvocationHandler;
  5 import java.lang.reflect.Method;
  6 import java.lang.reflect.Proxy;
  7 import java.lang.reflect.UndeclaredThrowableException;
  8 
  9 public final class $Proxy0 extends Proxy
 10   implements HelloService
 11 {
 12   //equals方法
 13   private static Method m1;
 14   //HelloService 的sayHello方法
 15   private static Method m3;
 16   //toString方法
 17   private static Method m2;
 18   //hashCode方法
 19   private static Method m0;
 20 
 21   //構造方法
 22   public $Proxy0(InvocationHandler paramInvocationHandler)
 23     throws 
 24   {
 25     super(paramInvocationHandler);
 26   }
 27 
 28   public final boolean equals(Object paramObject)
 29     throws 
 30   {
 31     try
 32     {
 33       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
 34     }
 35     catch (Error|RuntimeException localError)
 36     {
 37       throw localError;
 38     }
 39     catch (Throwable localThrowable)
 40     {
 41       throw new UndeclaredThrowableException(localThrowable);
 42     }
 43   }
 44 
 45   //調用了invocationHandler的invoke方法,invoke執行了HelloService 的sayHello方法
 46   public final void sayHello()
 47     throws 
 48   {
 49     try
 50     {
 51       this.h.invoke(this, m3, null);
 52       return;
 53     }
 54     catch (Error|RuntimeException localError)
 55     {
 56       throw localError;
 57     }
 58     catch (Throwable localThrowable)
 59     {
 60       throw new UndeclaredThrowableException(localThrowable);
 61     }
 62   }
 63 
 64   public final String toString()
 65     throws 
 66   {
 67     try
 68     {
 69       return (String)this.h.invoke(this, m2, null);
 70     }
 71     catch (Error|RuntimeException localError)
 72     {
 73       throw localError;
 74     }
 75     catch (Throwable localThrowable)
 76     {
 77       throw new UndeclaredThrowableException(localThrowable);
 78     }
 79   }
 80 
 81   public final int hashCode()
 82     throws 
 83   {
 84     try
 85     {
 86       return ((Integer)this.h.invoke(this, m0, null)).intValue();
 87     }
 88     catch (Error|RuntimeException localError)
 89     {
 90       throw localError;
 91     }
 92     catch (Throwable localThrowable)
 93     {
 94       throw new UndeclaredThrowableException(localThrowable);
 95     }
 96   }
 97 
 98   static
 99   {
100     try
101     {
102       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
103       m3 = Class.forName("com.doubibi.framework.util.proxy.HelloService").getMethod("sayHello", new Class[0]);
104       m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
105       m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
106       return;
107     }
108     catch (NoSuchMethodException localNoSuchMethodException)
109     {
110       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
111     }
112     catch (ClassNotFoundException localClassNotFoundException)
113     {
114       throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
115     }
116   }
117 }
$Proxy0

代理類$Proxy0調用了invocationHandler也就是的helloServiceProxy的invoke方法,而invoke通過反射執行了HelloService 的sayHello方法也就是HelloServiceImpl的sayHello方法。

自此java動態代理源碼分析完成,筆者對動態代理理解更加深刻,如有不當之處還請各位讀者指正


免責聲明!

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



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