动态代理:动态代理本质是一个动态生成增强的被代理对象的过程。
静态代理模式:
(1):首先我们有一个普通的接口和一个实现了这个接口的Class类:但这样就需要为每个普通类实现一个代理类,如果大量使用会导致类的急剧膨胀。另外在实现代理类时我们需要清楚普通类的构成。因此我们需要动态代理。
动态代理:
首先我们需要清晰我们要解决的问题是什么:我们的目的是对任意一个实现了某个接口(或者某几个)的普通的java类A的任意一个方法a(),当我们调用A.a()时候,系统可以在执行A.a()之前或者之后时自动的完成其他的一些固定的工作:如权限验证,日志记录。并且,这些工作在类A中完全没有代码涉及,即这些工作和类A完全解耦,类A对这些工作毫不知情。
(1)因为类A对这些额外工作毫不知情,所以我们依然需要一个代理类,这个代理类中实现了额外工作的逻辑(权限验证、日志记录等),但是为了改变静态代理模式中需要为每个普通类见一个代理类的情况,我们这个代理类需要能够传入任何类型,所以其构造函数类型为Object。
JDK为我们内置了一个这样的代理接口:InvocationHandler。在java.lang.reflect包下:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
如果要使用动态代理,我们首先必须实现一个继承这个接口的代理类:
public class MyInvocationHandler implements InvocationHandler {
private Object A;
public MyInvocationHandler(Object A) {
this.A=A;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
{
// 在目标对象的方法执行之前处理工作
System.out.println("------------------before------------------");
// 执行目标对象的方法
Object result = null;
result = method.invoke(A, args);
// 在目标对象的方法执行之后处理工作
System.out.println("-------------------after------------------");
return result;
}
}
可见我们可以将任意类型的实例传入这个代理类中,并且必须要传入一个类型的实例。
(2)现在我们已经有了一个代理类的实例MyInvoke,这个代理类实例传入的是一个实现foo接口的类型实例:
Foo foo=new Fooclass();
MyInvocationHandler MyInvoke=new MyInvocationHandler(foo);
这个代理类的invoke()方法中就是其他工作与调用方法的结合,我们可以在这儿写入我们调用方法时需要完成的额外工作,如权限验证、日志记录等
public Object invoke(Object proxy, Method method, Object[] args)
{
// 在目标对象的方法执行之前处理工作
System.out.println("------------------before------------------");
// 执行目标对象的方法
Object result = null;
result = method.invoke(A, args);
// 在目标对象的方法执行之后处理工作
System.out.println("-------------------after------------------");
return result;
}
但是目前为止我们看到没有任何入口调用这个invoke(Objectproxy, Method method, Object[] args)方法。并且我们也不可能主动的调用invoke方法。我们再次明确我们的目的是:当我们执行A.a()时,系统自动的执行其他的额外工作,而不需要我们显示的调用额外的方法。因此我们需要的是一个可以调用invoke方法foo类型对象,而不是一个MyInvocationHandler对象。所以我们需要根据这个代理类对象动态生成一个可以调用invoke方法并且是隐式调用的foo类型的对象。
public class Proxy implements java.io.Serializable {
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces);
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
}
重点是两个static方法getProxyClass和newProxyInstance。
Class cl = getProxyClass(loader, interfaces);
//调用getProxyClass方法,返回一/动态生成的class对象。
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
//返回一个object类型实例,可强制转换为传入的所有接口的任意一个接口类型
}
而getProxyClass方法则是整个动态代理的核心,核心代码为://生成动态对象的字节码流。
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
//调用本地方法defineClass0()生成class对象。
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
所以通过这两个方法就可以生成一个和传入实例继承接口类型相同的动态对象,如下://返回一个object对象,可以转换为传入代理类的类型所继承的所有接口中的任意一个。
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
Foo.getClass().getInterfaces(), this);
//this就是创建的代理类MyInvocationHandler实例。
}
测试main函数:
public class Proxy_main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Foo foo=new Fooclass();
MyInvocationHandler MyInvoke=new MyInvocationHandler(foo);
Foo fooclass=(Foo)MyInvoke.getProxy();
fooclass.printMessage("poxy");
}
}
输出如下:
------------------before------------------
This is Object FooClass~!poxy
-------------------after------------------
可见此时我们实现了目的:在调用fooclass.printMessage("poxy")时,系统自动执行了其他额外工作。且该中实现方式中实现了代理类和普通类型的完全解耦。普通类只需完成自己的逻辑。额外工作完全在代理类中的invoke()方法中实现,且只需实现一次即可。
现在我们总结一下使用动态代理的步骤: