动态代理通俗解释:
A接口有c方法,类B实现A接口,原本应该是执行B类中的c方法,可现在不这样做,可以先声明产生B类的代理类B',由它来冒充B类的“兄弟”并“实现”A接口, 对外界来说B'应该也有c方法,可当真正调用它的时候, 它会去执行与它关联InvocationHandler的invoke()方法, 在这个方法里面你可以做很多事情。
Java怎样实现动态代理呢
第一步,我们要有一个接口,还要有一个接口的实现类,而这个实现类就是我们要代理的类。
public interface Subject
{
public void request();
}
public class RealSubject implements Subject
{
public void request()
{
System.out.println("From real subject!");
}
}
第二步,我们要自己写一个代理类,它的特点是实现了InvocationHandler接口, 因为代理类的实例在调用实现类的方法的时候,不是去调用真正的实现类的这个方法, 而是调用代理类的invoke()方法,在这个方法中才调用真正的实现类的方法。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 该代理类的内部属性是Object类型,实际使用的时候通过该类的构造方法传递进来一个对象
* 此外,该类还实现了invoke方法,该方法中的method.invoke其实就是调用被代理对象的将要
* 执行的方法,方法参数是sub,表示该方法从属于sub,通过动态代理类,我们可以在执行真实对象的方法前后
* 加入自己的一些额外方法,这里在方法调用前后打印一句话。
*
*/
public class DynamicSubject implements InvocationHandler
{
private Object sub;
public DynamicSubject(Object obj)
{
this.sub = obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("before calling: " + method);
method.invoke(sub, args);
System.out.println(args == null);
System.out.println("after calling: " + method);
return null;
}
}
上述方法体中method.invoke(owner, args)的解释:执行该method.invoke方法的参数是执行这个方法的对象owner,参数数组args,可以这么理解:owner对象中带有参数args的method方法。返回值是Object,也就是该方法的返回值。
第三步,客户端要用代理类的实例去调用实现类的方法。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client
{
public static void main(String[] args)
{
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new DynamicSubject(realSubject);
Class<?> classType = handler.getClass();
// newProxyInstance()动态生成一个类并加载到内存
// 加载到内存要使用加载器,第一个参数是一个类加载器
Subject subject = (Subject) Proxy.newProxyInstance(classType
.getClassLoader(), realSubject.getClass().getInterfaces(),
handler);
subject.request();
System.out.println(subject.getClass());
}
}
对第三步的解释
主要是以下代码:
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
该方法主要做了如下工作:
- 根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces) 创建代理类$Proxy0,该代理类实现了预先定义的接口(如上面的Subject),并继承了Proxy类。
public final class $Proxy0 extends Proxy implements Subject
实例化$Proxy0(创建代理对象)并在构造方法中把 InvocationHandler(这里handler 是它的实例)传过去
$Proxy0调用父类Proxy的构造器,为InvocationHandler 赋值:
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
========================================================
class Proxy
{
protected InvocationHandler h;
protected Proxy(InvocationHandler h)
{
this.h = h;
}
}
- 将这个$Proxy0类强制转型成接口类型,当执行接口中的方法时(如上文强转成Subject后调用request()方法),就调用了$Proxy0类中实现的接口方法,在该方法中会调用父类Proxy中的invoke()方法,即InvocationHandler.invoke(),达到做一些其他工作的效果。
public final void request()
{
try
{
//m是通过反射得到的方法名 Method类型
super.h.invoke(this, m, null);
return;
}
catch (Error e)
{
}
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}