本文总结摘自刘伟老师的《设计模式》和程杰老师的《大话设计模式》
在看本文动态代理前建议看前一篇代理模式的讲解。
动态代理
动态代理是一种较为高级的代理模式,它的典型应用就是Spring AOP。
在传统的代理模式中,客户端通过ProxySubject调用RealSubject类的request()方法,同时还在代理类中封装了其他方法(如preRequest()和postRequest()),可以处理一些其他问题。如果按照这种方法使用代理模式,那么被代理对象类必须是事先已经存在的,并将其作为代理对象的内部成员属性。如果一个被代理对象必须对应一个代理类角色,这将导致系统中的类的个数急剧增加,因此需要想办法减少系统中类的个数,此外,如何在事先不知道被代理对象的情况下使用代理对象,这都是动态代理需要解决的问题。
java动态代理实现相关类位于java.lang.reflect包,主要涉及两个类:
(1)InvocationHandler接口。它是代理实例的调用处理程序实现的接口,该接口中定义了如下方法:
public Object invoke(Object proxy,Method method,Object[] args)throws Throwable;
invoke()方法中第一个参数proxy表示代理类,第二个参method表示需要代理的方法,第三个参数args表示代理方法的参数数组。
(2)Proxy类。该类即为动态代理类,该类最常用的方法为:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
newProxyInstance()方法用于根据传入的接口类型interfaces返回一个动态创建的代理类的实例,方法中第一个参数loader表示代理类的类加载器,第二个参数interfaces表示代理类实现的接口列表(与被代理类的接口列表一致),第三个参数h表示所指派的调用处理程序类。
下面通过一个简单实例来学习如何使用动态代理模式,现在有两个被代理类分别是RealSubjectA和RealSubjectB,它们对于在抽象主题类中定义的抽象方法request()提供了不同的实现,在不断增加新的代理类的情况下,使得客户端通过一个动态代理类来动态选择所代理的被代理对象,实现类图如下:
实现代码如下:
(1)抽象主题类
public interface AbstractSubject
{
public void request();
}
(2)被代理类A(真实主题类A)
public class RealSubjectA implements AbstractSubject
{
public void request()
{
System.out.println("真实主题类A!");
}
}
(3)被代理类B(真实主题类B)
public class RealSubjectB implements AbstractSubject
{
public void request()
{
System.out.println("真实主题类B!");
}
}
(4)动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class DynamicProxy implements InvocationHandler
{
private Object obj;
public DynamicProxy(){}
public DynamicProxy(Object obj)
{
this.obj=obj;
}
//实现invoke()方法,调用在被代理类中定义的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
preRequest();
method.invoke(obj, args);
postRequest();
return null;
}
public void preRequest(){
System.out.println("调用之前!");
}
public void postRequest(){
System.out.println("调用之后!");
}
}
(5)客户端测试类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client
{
public static void main(String args[])
{
InvocationHandler handler =null;
AbstractSubject subject=null;
handler=new DynamicProxy(new RealSubjectA());
subject=(AbstractSubject)Proxy.newProxyInstance(AbstractSubject.class.getClassLoader(), new Class[]{AbstractSubject.class}, handler);
subject.request();
System.out.println("------------------------------");
handler=new DynamicProxy(new RealSubjectB());
subject=(AbstractSubject)Proxy.newProxyInstance(AbstractSubject.class.getClassLoader(), new Class[]{AbstractSubject.class}, handler);
subject.request();
}
}
在动态代理模式中,对于多个被代理对象,只需要提供一个动态代理类,在动态代理类中无须维护一个与被代理类的引用,用户可以根据需要自定义新的被代理类,在系统设计和客户端编程实现时也无须关心被代理类,系统灵活性和可扩展性更好。