一,为什么需要动态代理?
在静态代理中一个代理类只能为一个接口服务,如果有很多个接口的话则就需要很多的代理类,而且所有的代理操作除了调用的方法不一样之外,其他的操作都一样,这就造成多个代理类的代码重复,为了解决静态代理的这个问题就有了动态代理。动态代理可以通过一个代理类完成全部的代理功能。
二,怎样实现动态代理?
要实现动态代理就需要java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类的支持。
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject,InvocationHandler提供了一个
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable参数: proxy - 在其上调用方法的代理实例 method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。 args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。 返回: 从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为 null 并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出 NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出 ClassCastException。 Proxy类是专门完成代理的操作类,可以通过此类为一个或者多个接口动态地生成实现类,此类实现了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。此方法相当于:
Proxy.getProxyClass(loader, interfaces).
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
Proxy.newProxyInstance 抛出 IllegalArgumentException,原因与 Proxy.getProxyClass 相同。
参数:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
ClassLoader是一个类加载器,如果要得到一个加载器的对象则需要使用Class类完成。
例子程序如下:
import java.lang.reflect.InvocationHandler ;
import java.lang.reflect.Proxy ;
import java.lang.reflect.Method ;
interface Subject{
public String say(String name,int age) ; // 定义抽象方法say
}
class RealSubject implements Subject{ // 实现接口
public String say(String name,int age){
return "姓名:" + name + ",年龄:" + age ;
}
};
class MyInvocationHandler implements InvocationHandler{
private Object obj ;
public Object bind(Object obj){
this.obj = obj ; // 真实主题类
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this) ;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
Object temp = method.invoke(this.obj,args) ; // 调用方法
return temp ;
}
};
public class DynaProxyDemo{
public static void main(String args[]){
Subject sub = (Subject)new MyInvocationHandler().bind(new RealSubject()) ;
String info = sub.say("张三",30) ;
System.out.println(info) ;
}
}; |