为什么jdk动态代理类必须实现接口?

350 阅读1分钟

一. 我写了一个Jdk动态代理类来测试jdk动态代理类的过程

  1. IRentingHouse rentingHouse = new RentingHouseImpl () ; // 委托对象---委托方
public class RentingHouseImpl implements IRentingHouse {

 @Override

    public void rentHosue () {

 System.out.println ( "我要租用一室一厅的房子" ) ;

    }

 }



public interface IRentingHouse {

 void rentHosue () ;

 }
  1. 动态代理工厂中创建动态代理对象方法
 /**

 * Jdk动态代理

 * @param obj  委托对象

 * @return   代理对象

 */

public Object getJdkProxy ( Object obj ) {



 // 获取代理对象

 return  Proxy.newProxyInstance( obj.getClass () .getClassLoader () , obj.getClass () .getInterfaces () ,

            new InvocationHandler () {

 @Override

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

 Object result = null;



                    // 写增强逻辑

 System.out.println ( "中介(代理)收取服务费3000元" ) ;

                    // 调用原有业务逻辑

 result = method.invoke ( obj,args ) ;



                    System.out.println ( "客户信息卖了3毛钱" ) ;



                    return result;

                }

 }) ;



 }
  1. 保存 JDK 动态代理生产的类(能看到生成的动态代理对象)
 /**

 * 保存 JDK 动态代理生产的类

 * @param filePath 保存路径,默认在项目路径下生成 $Proxy0.class 文件

 */

private static void saveProxyFile ( String... filePath ) {

 if ( filePath.length == 0 ) {

 System.getProperties() .put ( "sun.misc.ProxyGenerator.saveGeneratedFiles", "true" ) ;

    } else {

 FileOutputStream out = null;

        try {

 byte [] classFile = ProxyGenerator.generateProxyClass( "$Proxy0", RentingHouseImpl.class.getInterfaces ()) ;

            out = new FileOutputStream ( filePath [ 0 ] + "$Proxy0.class" ) ;

            out.write ( classFile ) ;

        } catch ( Exception e ) {

 e.printStackTrace () ;

        } finally {

 try {

 if ( out != null ) {

 out.flush () ;

                    out.close () ;

                }

 } catch ( IOException e ) {

 e.printStackTrace () ;

            }

 }

 }

 }
  1. 入口
public static void main ( String [] args ) {



 saveProxyFile() ;



    IRentingHouse rentingHouse = new RentingHouseImpl () ;  // 委托对象---委托方



 // 从代理对象工厂获取代理对象

 IRentingHouse jdkProxy = ( IRentingHouse ) ProxyFactory.getInstance() .getJdkProxy ( rentingHouse ) ;



    jdkProxy.rentHosue () ;





 }

二. 源码追踪

  1. Proxy.newProxyInstance()
  2. Class < ? > cl = getProxyClass0( loader, intfs ) ;

  1. proxyClassCache.get ( loader, interfaces ) ;==>V value = supplier.get () ;==>Objects.requireNonNull( valueFactory.apply ( key, parameter )) ;
  2. 代码进入java.lang.reflect.Proxy中的类ProxyClassFactory#apply()。

此类line.639行

byte [] proxyClassFile = ProxyGenerator.generateProxyClass(

 proxyName, interfaces, accessFlags ) ;

    

 # 组装了一个byte类型代理类。在后面传了回去通过反编译

因此我们将byte [] proxyClassFile 反编译,则可以得到代理对象的类。在saveProxyFile中可以直接调用方法ProxyGenerator.generateProxyClass(),将反编译的类保存起来。

三.代理类

 //

 // Source code recreated from a .class file by IntelliJ IDEA

 // (powered by Fernflower decompiler)

 //



package com.sun.proxy;



import designpattern.proxy.dynamicproxy.IRentingHouse;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.lang.reflect.UndeclaredThrowableException;



public final class $Proxy0 extends Proxy implements IRentingHouse {

    private static Method m1;

    private static Method m3;

    private static Method m2;

    private static Method m0;



    public $Proxy0(InvocationHandler var1) throws  {

        super(var1);

    }



    public final boolean equals(Object var1) throws  {

        try {

            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});

        } catch (RuntimeException | Error var3) {

            throw var3;

        } catch (Throwable var4) {

            throw new UndeclaredThrowableException(var4);

        }

    }



    public final void rentHosue() throws  {

        try {

            super.h.invoke(this, m3, (Object[])null);

        } catch (RuntimeException | Error var2) {

            throw var2;

        } catch (Throwable var3) {

            throw new UndeclaredThrowableException(var3);

        }

    }



    public final String toString() throws  {

        try {

            return (String)super.h.invoke(this, m2, (Object[])null);

        } catch (RuntimeException | Error var2) {

            throw var2;

        } catch (Throwable var3) {

            throw new UndeclaredThrowableException(var3);

        }

    }



    public final int hashCode() throws  {

        try {

            return (Integer)super.h.invoke(this, m0, (Object[])null);

        } catch (RuntimeException | Error var2) {

            throw var2;

        } catch (Throwable var3) {

            throw new UndeclaredThrowableException(var3);

        }

    }



    static {

        try {

            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));

            m3 = Class.forName("designpattern.proxy.dynamicproxy.IRentingHouse").getMethod("rentHosue");

            m2 = Class.forName("java.lang.Object").getMethod("toString");

            m0 = Class.forName("java.lang.Object").getMethod("hashCode");

        } catch (NoSuchMethodException var2) {

            throw new NoSuchMethodError(var2.getMessage());

        } catch (ClassNotFoundException var3) {

            throw new NoClassDefFoundError(var3.getMessage());

        }

    }

}

可见:

public final class $Proxy0 extends Proxy implements IRentingHouse {

继承了Proxy,实现了IRentingHouse

结论分析:

因为JDK动态代理类已经继承了Proxy这个类,所以只能通过接口来与被代理类建立联系(两个类建立起联系,一是继承的关系【jdk已经不能通过这个方式了,因为java仅支持单继承】,另一种就是实现同一个接口【JDK动态代理选这种】),所以必须要求被代理类也得实现一个接口,这样的话代理类与被代理类就能通过这个接口建立联系了