目的:
对被代理的对象进行统一的访问控制,或功能增强。
静态代理
抽象角色(Subject)类:
abstract public class Subject {
abstract public void request();
}
代理角色(ProxySubject)类:
public class ProxySubject extends Subject {
private RealSubject realSubject;
public ProxySubject(){}
public void request() {
if (realSubject == null){
realSubject = new RealSubject();
}
realSubject.request();
}
}
真实角色(RealSubject)类:
public class RealSubject extends Subject {
public RealSubject(){}
public void request() {
System.out.println("真实的请求.");
}
}
客户端的调用代码:
Subject sub = new ProxySubject();
sub.request();
总结:
静态代理必须明确得到被代理的类。每一个抽象接口,对应这个真实类和代理类,会导致类膨胀。
动态代理
首先创建抽象角色:
public interface Subject {
void doSomething();
void somethingElse(String arg);
}
接下来创建具体角色:
public class RealSubject implements Subject{
@Override
public void doSomething() {
System.out.println("doSomething");
}
@Override
public void somethingElse(String arg) {
System.out.println("somethingElse: " + arg);
}
}
接下来是创建一个InvocationHandler接口的实现:
public class DynamicProxyHandler implements InvocationHandler{
private Object proxied;
public DynamicProxyHandler(Object proxied){
this.proxied = proxied;
}
/**
* invoke()方法中传递进来了代理对象,以防你需要区分请求的来源
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("*** proxy ***" + proxy.getClass());
System.out.println("*** method ***" + method);
System.out.println("*** args ***" + args);
// 可以在这里做一些处理,如查看方法名,查看方法签名的其他方面,甚至可以搜索特定的参数值
if(method.getName().equals("interesting"))
System.out.println("Proxy detected the interesting method.");
// 将请求转发给被代理的真实对象,并传入必须的参数
return method.invoke(proxied, args);
}
}
最后在main方法中创建动态代理对象,并通过动态代理调用真实角色的方法:
public class SimpleDynamicProxy {
public static void consumer(Subject subject){
subject.doSomething();
subject.somethingElse("haha~~");
}
public static void main(String[] args){
// 创建真实的对象
RealSubject real = new RealSubject();
consumer(real);
// 通过调用该方法创建动态代理
Subject proxy = (Subject)Proxy.newProxyInstance(
Subject.class.getClassLoader(), // 类加载器
new Class[]{Subject.class}, // 你希望该代理实现的接口列表
new DynamicProxyHandler(real)); // InvocationHandler接口的一个实现
consumer(proxy);
}
}
第一个consumer(real)输出为:
doSomething
somethingElse: haha~~
第二个consumer(proxy)输出为:
*** proxy ***class com.sun.proxy.$Proxy0
*** method ***public abstract void com.yunsheng.Subject.doSomething()
*** args ***null
doSomething
*** proxy ***class com.sun.proxy.$Proxy0
*** method ***public abstract void com.yunsheng.Subject.somethingElse(java.lang.String)
*** args ***[Ljava.lang.Object;@6b40443
somethingElse: haha~~
总结:
动态代理在执行时,将方法的调用先重定向到InvocationHandler的实现类中。在Proxy.newProxyInstance时生成代理对象。在对代理对象进行方法调用时,才将调用的方法名和参数传去invoke进行执行。