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的动态代理是必须依赖接口的。

 

转载于:https://www.cnblogs.com/penglaihaibiandexiaoxiami/p/8313327.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值