1.代理模式
在代理模式中,接活的就是代理,实际干事儿的就是被代理的对象,也就是说,接活的和干活的不是同一个对象。
这里举经典的火车站和火车票代售点为例来说明。
package testproxy;
public interface SellTicket {
public void sellTicket();
}
SellTicket接口只有一个卖票的方法,凡是实现了该接口的类,都有卖票的能力。首先,火车站有卖票的能力:
package testproxy;
public class RailwayStation implements SellTicket {
@Override
public void sellTicket() {
System.out.println("火车站售票");
}
}
然后,火车票代售点有卖票的能力:
package testproxy;
public class RailwayStationProxy implements SellTicket {
SellTicket sellTicket;
public RailwayStationProxy() {
this.sellTicket = new RailwayStation();
}
@Override
public void sellTicket() {
System.out.println("开始售票");
this.sellTicket.sellTicket();
System.out.println("售票成功");
}
}<span style="font-size:24px;">
</span>
与火车站不同的是,火车票代售点自己并没有票,实际上出票的是火车站。可见,代售点只是个接活的,也就是代理,火车站才是真正干活的对象,也就是被代理的对象。
下面是一个买票的客户:
package testproxy;
public class Client {
public static void main(String[] args) {
SellTicket sellTicket = new RailwayStationProxy();
sellTicket.sellTicket();
}
}
客户买票的过程是这样的:
开始售票
火车站售票
售票成功
可见,代理参与了售票活动,但是真正出票的是火车站。
总结一下代理模式:代理和被代理对象都向外宣称自己有干某件事的能力,供客户调用,所以它们必须继承同一个接口;但是,代理并没有真正干某件事儿的能力,所以,他需要有一个对被代理对象的引用,当客户让它干事儿时,它就让被代理对象去干。
2.JDK动态代理
JDK动态代理让我们不用创建代理类就能创建一个代理对象。
代理对象是通过java.lang.reflect.Proxy类的静态方法创建的:
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
它的参数分别是类加载器、宣称该代理有哪些能力的接口的Class数组和一个调用处理器。类加载器用于加载接口;调用处理器用于关联代理对象和被代理对象。调用处理器有下面这个方法:
invoke(Object proxy, Method method, Object[] args)
proxy是代理对象,method是客户端调用的代理对象的方法对应的Method对象,args是客户端传给调用方法的参数。客户端每次调用代理对象上的方法,都会触发调用处理器的invoke方法被调用。
这里同样用火车站和火车票代售点的例子来具体说明:
同样有一个用于宣称代理对象和被代理对象有何能力的接口:
package testproxy;
public interface SellTicket {
public void sellTicket();
}
然后是确实有售票能力的火车站:
package testproxy;
public class RailwayStation implements SellTicket {
@Override
public void sellTicket() {
System.out.println("火车站售票");
}
}
要实现动态代理,我们还需要一个调用处理器:
package testproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class SellTicketHandler implements InvocationHandler {
private Object target;
public SellTicketHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("开始售票");
method.invoke(target);
System.out.println("售票成功");
return null;
}
}
调用处理器的invoke方法调用了被代理对象上相应的方法。
接下来是在客户端,在客户端创建代理对象,并调用它上面的方法:
package testproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args) {
RailwayStation railwayStation = new RailwayStation();
InvocationHandler handler = new SellTicketHandler(railwayStation);
Class[] interfaces = new Class[] {SellTicket.class};
Object proxy = Proxy.newProxyInstance(handler.getClass().getClassLoader(),
interfaces, handler);
try {
Method method = SellTicket.class.getMethod("sellTicket");
method.invoke(proxy);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
开始售票
火车站售票
售票成功
最终总结:不管是代理模式,还是JDK的动态代理,都有这样几个元素:代理,被代理对象,以及宣称它们能力的接口;只是动态代理不需要显示创建代理类。