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; } }
接下来是在客户端,在客户端创建代理对象,并调用它上面的方法:
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的动态代理,都有这样几个元素:代理,被代理对象,以及宣称它们能力的接口;只是动态代理不需要显示创建代理类。