写在前面
看dubbo等各种大型框架源码时,发现其中都大量利用到代理模式
。按照之前自己对代理模式肤浅的理解,仅仅是对实际要调用的对象包装了一层,可是这么做的原因或者说好处到底是啥,一直不是很清楚。同时注意到Java中有动态代理
技术,这边文章顺到来梳理这些问题。
模式定义
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。
定义总是很抽象。代理模式不仅为另一个对象提供替身,同时还可以控制访问
,几种常见控制访问的方式如下
- 远程代理 控制访问远程对象
- 虚拟代理 控制访问创建开销大的资源
- 保护代理 基于权限控制对资源的访问
代码实战
1. 远程代理
Java RMI 技术。RMI提供了客户端辅助对象sub(桩),服务端辅助对象skeleton(骨架),不用亲自写任何网络或IO代码。
2. 虚拟代理
3. 保护代理
Java在java.lang.reflect包中有对代理的支持,该包可以在运行时动态的创建代理类,实现一个或多个接口,并将方法调用转发到所指定的类。因为实际的代理类是在运行时创建
的,故称该技术为动态代理
。
在本节,我们利用Java的动态代理技术创建保护代理
,类图如下:
定义接口
public interface PersonBean {
String getName();
String getGender();
String getInterests();
int getHotOrNotRating();
void setName(String name);
void setGender(String gender);
void setInterests(String interests);
void setHotOrNotRating(int rating);
}
实现接口
public class PersonBeanImpl implements PersonBean {
String name;
String gender;
String interests;
int rating;
int ratingCount = 0;
public PersonBeanImpl(String name) {
this.name = name;
}
public int getHotOrNotRating() {
if (ratingCount == 0) return 0;
return rating / ratingCount;
}
public void setHotOrNotRating(int rating) {
this.rating = rating;
ratingCount++;
}
}
创建InvocationHandler
public class OwnerInvocationHandler implements InvocationHandler {
PersonBean person;
public OwnerInvocationHandler(PersonBean person) {
this.person = person;
}
public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException {
try {
if (method.getName().startsWith("get")) {
return method.invoke(person, args);
} else if (method.getName().equals("setHotOrNotRating")) {
// 权限控制
throw new IllegalAccessException();
} else if (method.getName().startsWith("set")) {
return method.invoke(person, args);
}
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
创建Proxy对象
PersonBean getOwnerProxy(PersonBean person) {
return (PersonBean)Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new OwnerInvocationHandler(person));
}
测试代码(测试权限控制)
PersonBean joe = new PersonBeanImpl("Joe Javabean");
PersonBean ownerProxy = getOwnerProxy(joe);
System.out.println("Name is " + ownerProxy.getName());
ownerProxy.setInterests("swimming");
try {
ownerProxy.setHotOrNotRating(10);
} catch (Exception e) {
System.out.println("cat not set rating from owner proxy");
}
System.out.println("rating is " + ownerProxy.getHotOrNotRating());
小结
代理模式
要做的:控制和管理访问。
-
代理模式
为另外一个对象提供代表,控制客户对对象的访问 -
远程代理
管理客户和远程对象的交互 -
虚拟代理
控制访问实例化开销大的对象 -
保护代理
基于调用者控制对对象方法的访问
代理模式类似装饰者模式:前者控制访问,后者为对象加上行为。Java内置有代理支持,即动态代理