java 动态代理机制

JAVA动态代理

阅读前请先熟悉下面几点内容,可以帮助理解

一、JDK动态代理和CGLIB字节码生成的区别?

 * JDK动态代理只能对实现了接口的类生成代理,而不能针对类
 * CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
   因为是继承,所以该类或方法最好不要声明成final 


二、静态代理、动态代理区别?
静态代理:由程序员创建或工具生成代理类的源码,再编译代理类,即代理类和委托类的关系再程序运行前就已经存在。

动态代理:在运行期间使用动态生成字节码形式,动态创建代理类。使用的工具有 jdkproxy、cglibproxy 等。

三、设计模式中的代理模式。

------------分界线----------------

业务接口:

package jianlejun;

public interface IShopping {
public void buyMac();
public int buyMedicine(int num);
}

业务实现类:

package jianlejun;

public class Shopping implements IShopping {

	@Override
	public void buyMac() {
		System.out.println("帮我去香港买mac电脑~~");

	}

	@Override
	public int buyMedicine(int num) {
		System.out.println("帮我去日本买"+num+"份药物~~");
		return num;
	}

}

业务代理调用类:

package jianlejun;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 业务代理操作类,必须实现InvocationHandler接口
 * 最终真实方法的调用者都是该类完成
 * 代理对象调用业务方法时,会执行业务代理操作类的invoke()方法
 * 
 * @author 简乐君
 *
 */
public class ProxyHandler implements InvocationHandler{
	private Object targetClass;
	public ProxyHandler(Object targetClass) {
		this.targetClass = targetClass;
	}
	/**
	 * client中通过代理对象调用的业务方法都会作为method参数传递进来
	 * 代理对象调用业务方法时,只是执行了业务代理操作类的invoke()方法
	 * 必须显示调用method.invoke()方法,代理调用的业务方法才会被有效执行,
	 * proxy:代理对象
	 * method:代理对象执行的方法
	 * args:业务方法中的传递的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Class clazz = proxy.getClass();
		System.out.println("proxy所对应的类名为====>"+clazz.getName());
		String methodName = method.getName();
		System.out.println("代理调用的业务方法名为====>"+methodName);
		/**
		 * targetClass:方法所在的目标类;
		 * args:业务方法中传递的参数;
		 * 返回结果为业务方法的返回值
		 */
		Object returnObj = method.invoke(targetClass, args);
		
		return returnObj;
	}

}

客户端调用:

package jianlejun;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Client {
public static void main(String[] args) {
	IShopping is = new Shopping();//创建业务对象
	InvocationHandler ih = new ProxyHandler(is);//创建业务代理调用类
	ClassLoader loader = is.getClass().getClassLoader();//获取业务对象的类加载器,用于动态创建代理类
	Class []intf = is.getClass().getInterfaces();//获取业务对象所实现的接口列表,用于动态创建代理类
	IShopping proxy = (IShopping) Proxy.newProxyInstance(loader, intf, ih);//利用反射机制,在运行期间动态生成代理类
    proxy.buyMac();//通过代理对象调用业务方法,调用时执行的是InvocationHandler中的invoke()方法
    int num = proxy.buyMedicine(100);
}
}

输出结果:

proxy所对应的类名为====>com.sun.proxy.$Proxy0
代理调用的业务方法名为====>buyMac
帮我去香港买mac电脑~~
proxy所对应的类名为====>com.sun.proxy.$Proxy0
代理调用的业务方法名为====>buyMedicine
帮我去日本买100份药物~~

好,那假如现在我们想看看jdk动态代理机制生成的代理类长啥样,该怎么办呢?很简单,我们只需要在客户端加入一行代码即可:

System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");//打开保存proxy动态生成文件的开关

在工作空间下找到该项目,此时生成的class文件目录是比较特殊的,它跟src在同一级目录下,如果运行时报错

FileNotFoundException:com/sun/proxy/$proxy0.class(系统找不到指定路径),此时解决的方法可以在项目里与src同级下建包名为com.sun.proxy的包,再运行即可,然后运用反编译软件(http://jd.benow.ca)反编译该class文件即可。


来,我们来一睹动态生成的代理类的风采:

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import jianlejun.IShopping;

public final class $Proxy0
  extends Proxy
  implements IShopping
{
  private static Method m1;
  private static Method m4;
  private static Method m2;
  private static Method m3;
  private static Method m0;
  
  public $Proxy0(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int buyMedicine(int paramInt)
  {
    try
    {
      return ((Integer)this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) })).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void buyMac()
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m4 = Class.forName("jianlejun.IShopping").getMethod("buyMedicine", new Class[] { Integer.TYPE });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m3 = Class.forName("jianlejun.IShopping").getMethod("buyMac", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

现在来理解为什么代理对象调用业务方法时执行的是InvocationHandler中的invoke方法就很好理解了

public final int buyMedicine(int paramInt)
  {
    try
    {
      return ((Integer)this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) })).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
在方法内,并没有像静态代理模式一样直接调用业务类业务方法,而是委托给了InvocationHandler的invoke方法,并且后续也并没有显示调用业务类的业务方法,所以要在InvocationHandler的invoke方法中显示调用method.invoke()才算是正确调用了业务方法。切记切记
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值