1. 定义
为其他对象提供一种代理以控制这个对象的访问。
2. 结构图
Proxy:代理对象。通常具有如下功能。
实现与具体的目标对象一样的接口,这样就可以使用代理来代替具体的目标对象。
保存一个指向具体目标对象的引用,可以在需要的时候调用具体的目标对象。
可以控制对具体目标对象的访问,并可以负责创建和删除它。
Subject:目标接口,定义代理和具体目标对象的接口,这样就可以在任何使用具体目标对象的地方使用代理对象。
RealSubject:具体的目标对象,真正实现目标接口要求的功能。
3. 本质
代理模式的本质:控制对象访问。
4. Code Demo
Subject.java
package org.fool.proxy;
public interface Subject {
public void request();
}
RealSubject.java
package org.fool.proxy;
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("From real subject.");
}
}
ProxySubject.java
package org.fool.proxy;
public class ProxySubject implements Subject {
private RealSubject realSubject; // 代理角色所完成的事情
@Override
public void request() {
this.preRequest(); // 在真实角色操作之后所附加的操作(非必须)
if(null == realSubject) {
realSubject = new RealSubject();
}
realSubject.request(); // 真实角色所完成的事情
this.postRequest(); // 在真实角色之后所附加的操作(非必须)
}
private void preRequest() {
System.out.println("pre request");
}
private void postRequest() {
System.out.println("post request");
}
}
Client.java
package org.fool.proxy;
public class Client {
public static void main(String[] args) {
Subject subject = new ProxySubject();
subject.request();
}
}
5. 动态代理
Java对代理模式提供了内建的支持,在java.lang.reflect包下面,提供了一个Proxy的类和一个InvocationHandler的接口。
通常把前面自己实现的代理模式称为Java的静态代理。这种实现方式有一个较大的缺点,就是如果Subject接口发生变化,那么代理类和具体的目标实现都要变化,不是很灵活。而使用Java内建的对代理模式支持的功能来实现则没有这个问题。
通常把使用Java内建的对代理模式支持的功能来实现的代理称为Java的动态代理。动态代理跟静态代理相比,明显的变化是:静态代理实现的时候,在Subject接口上定义很多的方法,代理类里面自然也要实现很多方法;而动态代理实现的时候,虽然Subject接口上定义了很多方法,但是动态代理类始终只有一个invoke方法。这样,当Subject接口发生变化的时候,动态代理的接口就不需要跟着变化了。
Java的动态代理目前只能代理接口,基本的实现是依靠Java的反射机制和动态生成class的技术,来动态生成被代理的接口的实现对象。
代理模式在客户和被客户访问的对象之间,引入了一定程度的间接性,客户是直接使用代理,让代理来与被访问的对象进行交互。不同的代理类型,这种附加的间接性有不同的用途,也就具有不同的特点。
动态代理Demo
Subject.java
package org.fool.dynamicproxy;
public interface Subject {
public void request();
}
RealSubject.java
package org.fool.dynamicproxy;
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("From real subject...");
}
}
DynamicSubject.java
package org.fool.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicSubject implements InvocationHandler {
private Object subject;
public DynamicSubject(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling: " + method);
method.invoke(subject, args);
System.out.println("after calling: " + method);
return null;
}
}
Client.java
package org.fool.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
InvocationHandler handler = new DynamicSubject(realSubject);
Class<?> classType = handler.getClass();
Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(),
realSubject.getClass().getInterfaces(), handler);
subject.request();
}
}