代理模式的作用:为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理一般涉及到的角色:
--抽象角色:声明真实对象和代理对象的共同接口
--代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他操作,相当于对真实对象进行封装。
--真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
抽象角色
public abstract class Subject { public abstract void request(); } |
代理角色
public class ProxySubject extends Subject { private RealSubject realSubject; @Override public void request() { this.preRequest(); if(null == realSubject) { this.realSubject = new RealSubject(); } realSubject.request(); this.postRequest(); } private void preRequest() { System.out.println("proxy pre request"); } private void postRequest() { System.out.println("proxy post request"); } } |
真实角色
public class RealSubject extends Subject { @Override public void request() { System.out.println("From real subject"); } } |
测试
public class ProxyTest { public static void main(String[] args) { Subject proxy = new ProxySubject(); proxy.request(); } } |
动态代理
动态代理的关键的两个类Proxy和InvocationHandler
抽象角色
public interface Subject { public void request(); } |
真实角色
public class RealSubject implements Subject { @Override public void request() { System.out.println("From Real Subject"); } } |
动态代理角色
public class DynamicProxy implements
InvocationHandler { private Object sub; public DynamicProxy(Object sub) { this.sub = sub; } @Override public Object invoke(Object proxy,
Method method, Object[] args) throws Throwable { System.out.println("before invoking: " + method
); method.invoke(sub, args); System.out.println(null == args); System.out.println("after invoking: " +
method); return null; } } |
测试
public class Client { public static void main(String[] args) { RealSubject realSub = new RealSubject(); InvocationHandler handler = new
DynamicProxy(realSub); Class<?> classType =
handler.getClass(); Subject sub = (Subject)Proxy.newProxyInstance(classType.getClassLoader(), realSub.getClass().getInterfaces(),handler); sub.request(); System.out.println(classType.getClassLoader()); System.out.println(sub.getClass()); } } |
动态代理的创建步骤
1..创建一个实现InvocationHandler接口的类,它必须实现invoke方法。
public class CommonInvocationHandle implements
InvocationHandler { private Object target; public
CommonInvocationHandle(Object target) { super(); this.target = target; } public CommonInvocationHandle() { } public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy,
Method method, Object[] args) throws Throwable { return method.invoke(target, args); } } |
2.创建被代理的类以及接口
public interface Foo { public void doAction(); } public class FooImp1 implements Foo { @Override public void doAction() { System.out.println("From FooImp1 doAction"); } } public class FooImp2 implements Foo { @Override public void doAction() { System.out.println("From FooImp2 doAction"); } } |
3.通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法
public class FooProxyDemo { public static void main(String[] args) { //理解动态代理的前提是要理解代理模式。 //动态代理完成的事情还是代理模式里的代理角色, //只不过通过 动态生成代理角色的方式去执行(java运行器帮你完成了),而不是自己去定义一个代理角色类 //这样就提供了一个比较灵活的方式去使用代理,而不用担心 有多少个真实角色。 CommonInvocationHandle handle = new
CommonInvocationHandle(); Foo foo = null; handle.setTarget(new FooImp1());//可以使用反射去动态决定运行时使用哪个真实角色,那样的话,代码逻辑就不用改变。 foo = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class},handle); foo.doAction(); System.out.println("---------------"); handle.setTarget(new FooImp2()); foo = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class},handle); foo.doAction(); } } |
帮助理解动态代理
public class VectorProxy implements
InvocationHandler { private Object proxyObj; public VectorProxy(Object proxyObj) { this.proxyObj = proxyObj; } public static Object factory(Object obj) { Class<?> classType =
obj.getClass(); return Proxy.newProxyInstance(classType.getClassLoader(), classType.getInterfaces(),new
VectorProxy(obj)); } @Override public Object invoke(Object proxy,
Method method, Object[] args) throws Throwable { System.out.println("before invoking method: " + method); if(null != args) { for(Object obj : args) { System.out.println(obj); } } Object object = method.invoke(proxyObj, args); System.out.println("after invoking method: " + method); return object; } public static void main(String[] args) { List list = (List)factory(new Vector()); System.out.println(list.getClass().getName()); list.add("New"); list.add(" System.out.println(list); list.remove(0); System.out.println(list); } } |