阐述
为一个对象提供一个占位符或者是替身,用以控制对这个对象的访问;
使用代理模式创建代理对象,代理对象用以访问被代理的对象。被代理对象可以远程对象、创建时开销大的对象、需要安全控制的对象。
-
远程代理
远程代理作为另一个JVM上对象的本地代表。调用代理上方法时,远程代理通过网络将请求传输到远程,并将结果再通过网络传输到本地,后返回给调用方。 -
虚拟代理
虚拟代理作为创建时开销大的对象的代表。虚拟代理经常直到我们真正需要一个对象的时候,才会去创建这个对象。在对象创建前、创建中的时候,这个对象的访问都由虚拟代理代表。在对象创建完成之后,虚拟代理才会将对象的访问委托给它所代理的对象。- 缓存代理(Caching Proxy)
为开销大的运算结果提供暂时存储:它也允许多个客户共享结果,以减少计算或者网络延迟。
- 缓存代理(Caching Proxy)
-
保护代理
根据权限不同,控制对被代理对象的访问。- 防火墙代理(Firewall Proxy)
控制网络资源的访问,保护“主题”免于“坏客户”的侵害。 - 智能引用代理 (Smart Reference Proxy)
当主题被引用时,进行额外的动作,例如计算一个对象被引用的次数。
- 防火墙代理(Firewall Proxy)
原理
例子
//subject
public interface PersonBean {
String getName();
}
//real subject
public class PersonBeanImpl implements PersonBean {
private String name;
@Override
public String getName() {
return name;
}
}
//handler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class NotOwnerInvocationHandler implements InvocationHandler {
//持有project
private PersonBean personBean;
NotOwnerInvocationHandler(PersonBean personBean) {
this.personBean = personBean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("getIdCard".equals(method.getName())){
throw new IllegalArgumentException("又不是你的资料,你瞅啥");
}
return method.invoke(personBean,args);
}
}
import java.lang.reflect.Proxy;
public class ProxyUtil {
public static PersonBean getOwnerProxy(PersonBean personBean){
return (PersonBean) Proxy.newProxyInstance(
personBean.getClass().getClassLoader(),
personBean.getClass().getInterfaces(),
new OwnerInvocationHandler(personBean)
);
}
public static PersonBean getNotOwnerProxy(PersonBean personBean){
return (PersonBean) Proxy.newProxyInstance(
personBean.getClass().getClassLoader(),
personBean.getClass().getInterfaces(),
new NotOwnerInvocationHandler(personBean)
);
}
}
//test
private void drive(){
PersonBean tom = new PersonBeanImpl("tom");
PersonBean ownerProxy = ProxyUtil.getOwnerProxy(tom);
System.out.println("ownerProxy.getIdCard() = " + ownerProxy.getIdCard());
PersonBean notOwnerProxy = ProxyUtil.getNotOwnerProxy(tom);
try {
System.out.println("notOwnerProxy = " + notOwnerProxy.getIdCard());
} catch (Exception e) {
e.printStackTrace();
}
}
总结
- 你以为你用的是Object,但其实你用的是ProxyObject。“I am watching you , I can touch you .’”
- Proxy 和 InvocationHandler 都在 java.lang.reflect
- Proxy创建代理对象,InvocationHandler可以决定是否要将请求真正委托给代理对象。