zoukankan      html  css  js  c++  java
  • jdk动态代理源码分析(二)---依赖接口的实现

    接上文,为什么JDK的动态代理需要依赖接口的实现呢?先来一段测试代码看看不依赖接口为报什么错。

    Hello类不再实现sayHello接口:

    package com.xiaosong.proxy.demo.service.impl;
    
    public class Hello {
    
    	public void sayHello() {
    		// TODO Auto-generated method stub
    		System.out.println("Hello KuGou!");
    	}
    }
    

    测试类改为:

    package com.xiaosong.proxy.demo.test;
    
    import com.xiaosong.proxy.demo.jdkproxy.MyInvocationHandler;
    import com.xiaosong.proxy.demo.service.impl.Hello;
    
    public class TestProxy {
    
    	public static void main(String[] args) {
    		
    		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
    		//新建一个service实现类对象
    //		IHello hello = new Hello();
    		Hello hello = new Hello();
    		//传入服务实现类对象Hello、InvocationHandler对象(代理类的具体操作类) 来获取一个代理类实例
    		MyInvocationHandler my = new MyInvocationHandler(hello);
    //		IHello helloProxy = (IHello) my.getProxyObject();
    		Hello helloProxy = (Hello) my.getProxyObject();
    		
    		helloProxy.sayHello();
    		
    	}
    
    }
    

     运行结果如下:

    Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.xiaosong.proxy.demo.service.impl.Hello
        at com.xiaosong.proxy.demo.test.TestProxy.main(TestProxy.java:18)

    结果是$Proxy0 无法强制转换为Hello 类。那么$Proxy 是个什么东西呢?

    代码中添加:System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

    并在项目根目录下创建:

    ,就会在运行期生成$Proxy 类了。进行反编译结果如下:

    package com.sun.proxy;
    
    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
    {
      private static Method m1;
      private static Method m0;
      private static Method m2;
    
      public $Proxy0(InvocationHandler paramInvocationHandler)
        throws 
      {
        super(paramInvocationHandler);
      }
    
      public final boolean equals(Object paramObject)
        throws 
      {
        try
        {
          return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (RuntimeException localRuntimeException)
        {
          throw localRuntimeException;
        }
        catch (Throwable localThrowable)
        {
        }
        throw new UndeclaredThrowableException(localThrowable);
      }
    
      public final int hashCode()
        throws 
      {
        try
        {
          return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (RuntimeException localRuntimeException)
        {
          throw localRuntimeException;
        }
        catch (Throwable localThrowable)
        {
        }
        throw new UndeclaredThrowableException(localThrowable);
      }
    
      public final String toString()
        throws 
      {
        try
        {
          return (String)this.h.invoke(this, m2, null);
        }
        catch (RuntimeException localRuntimeException)
        {
          throw localRuntimeException;
        }
        catch (Throwable localThrowable)
        {
        }
        throw new UndeclaredThrowableException(localThrowable);
      }
    
      static
      {
        try
        {
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
        }
        throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
      }
    }
    

      可以看出$Proxy就是一个Proxy的子类,和Hello类没有任何关系,肯定无法强转。那么正常情况下的$Proxy 又是个什么东西呢?

    package com.sun.proxy;
    
    import com.xiaosong.proxy.demo.service.IHello;
    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 IHello
    {
    //生成四个方法作为新代理类中的属性。包括hashcode,equals,tostring 和 接口实现方法。 private static Method m3; private static Method m1; private static Method m0; private static Method m2;
    //这个构造函数指向父类中Proxy中的构造函数,查看Proxy的对应构造函数是Protected修饰的,是只允许子类调用 public $Proxy0(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } //实现接口里的方法 public final void sayHello() throws { try {
    //这里很关键,h 指的就是构造函数中的InvocationHandler类,这个类可以是看做是代理类的具体实现类。每次调用sayHello方法都会自动去调用代理类的具体实现类中的invoke方法。 this.h.invoke(this, m3, null); return; } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } public final boolean equals(Object paramObject) throws { try { return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } public final int hashCode() throws { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } public final String toString() throws { try { return (String)this.h.invoke(this, m2, null); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } static { try { m3 = Class.forName("com.xiaosong.proxy.demo.service.IHello").getMethod("sayHello", new Class[0]); m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { } throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } }

     可以看出,不一样的是,这个$Proxy 是实现了IHello接口,自然是能够转成IHello对象了。继续阅读这个$Proxy类中内容,详见上面代码注释。可以看出这里代理类继承了Proxy类,对sayHello方法的调用是通过传入的接口的反射来实现的。所以jdk的动态代理是必须依赖接口的。

  • 相关阅读:
    在Java当中如何优雅地处理临时文件
    lombok插件不建议使用的原因
    linux系统下修改tomcat的端口号时,需要修改的地方
    linux系统下报错为:直接在tomcat的bin目录下生成一个错误文件。
    Linux下修改tomcat端口号
    python实现断点续传下载文件
    Python中下划线---完全解读
    linux  指令 备注
    Linux下高并发socket最大连接数所受的各种限制
    python和pywin32实现窗口查找、遍历和点击
  • 原文地址:https://www.cnblogs.com/penglaihaibiandexiaoxiami/p/8313327.html
Copyright © 2011-2022 走看看