代理模式为其他对象提供一种代理以控制对这个对象的访问。使用代理模式常见的原因是希望只有在我们确实需要对象时才对它进行创建和初始化。但是随着AOP技术的发展,代理技术也被用于运行时为对象添加新的特性或者进行全局的特性设置,如为某些特定命名或指定的类方法提供事务处理,为系统的所有类添加日志管理等批量功能,或者使用Java的RMI实现分布式功能。
常见的代理又分为多种模式:远程代理,Java中的RMI技术就是这种,利用网络流传递对象对象,在本地使用的是对象的代理而不是真实的对象;虚代理,根据需要创建很大的对象,如文件对象等;保护代理,用于控制原始对象的访问,根据不同的权限来保护原始对象;智能指引,如C++中的智能指针。
public interface Subject {
public void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("Real load the image.");
}
}
public class StaticProxy implements Subject {
private Subject realSubject = null;
public StaticProxy(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
if (realSubject != null) {
System.out.println("Do some extra job1!");
realSubject.request();
System.out.println("Do some extra job2!");
} else {
throw new RuntimeException("Proxy haven't initialed!");
}
}
}
public class StaticClient {
public void staticProxyTest() {
// use real object
RealSubject real = new RealSubject();
doSomeJob(real);
// use proxy
Subject proxy = new StaticProxy(new RealSubject());
doSomeJob(proxy);
}
// test method
public void doSomeJob(Subject subject) {
subject.request();
}
}
这是最简单的一种代理模式,通过让代理对象StaticProxy和RealSubject都实现相同的接口Subject,这样代理对象和实际对象就是相同的类型,在实际使用时就可以用代理对象来替代实际对象了。
另外,在Java中还支持动态代理的方式:
class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(proxy.getClass());
System.out.println("Do some extra job1!");
Object obj = method.invoke(proxied, args);
System.out.println("Do some extra job2!");
return obj;
}
}
public class DynamicClient {
@Test
public void dynamicProxyTest() {
RealSubject real = new RealSubject();
Subject proxy = (Subject) proxy(real, Subject.class);
proxy.request();
}
public <T> Object proxy(Object real, Class<T> clazz){
return Proxy.newProxyInstance(clazz.getClassLoader(),
new Class[] { clazz },
new DynamicProxyHandler(real));
}
}
动态代理是通过实现DynamicProxyHandler,然后调用Proxy类中的newProxyInstance方法,这个方法会根据类的二进制流生成新的对象,并通过实现DynamicProxyHandler的类提供的proxy方法,为生成的Proxy对象添加新功能。
相对于静态代理来说,动态代理更加灵活,当需要为新类型添加代理类时,静态代理需要添加新的代理类,这些代理类要实现被代理类的接口,也就意味着会产生大量的代理类。而动态代理却不需要这样,只需要构造好InvocationHandler的实现类,并把合适的Class对象传入,任意对象的代理都可以使用同一个InvocationHandler的实现类。
此外,Spring等框架中代理被大量使用,它们的实现方式是通过cglib等字节码生成技术来动态生成指定类的子类,并在子类中拦截父类的方法,并将子类作为父类的代理。