一 代理模式
定义:在访问目标对象的时候,提供一种间接访问的方法,通过代理对象去访问目标对象,达到客户端的目的。
好处:保护目标对象;在目标对象的行为基础上,代理对象可以增加自己的处理,使得同一个目标对象可以满足不同的客户端的目的。
代理模式的模型:
涉及三个角色:
RealSubject:目标对象,也是真正要做事情的人。
Proxy:代理对象,持有对目标对象的引用,暴露给客户端,通过操作目标对象来完成客户端的目的。并且,代理对象可以在操作目标对象的前后做一些自定义的行为,灵活扩展了目标对象。
Subject:目标对象和代理对象的抽象,以便在任何使用目标对象的地方都可以使用代理对象。Subject可以是一个接口也可以是一个抽象类。
二 静态代理
以最简单的形式实现上述模型
public interface Subject {
void doRequst();
}
public class RealSubject implements Subject {
@Override
public void doRequst() {
System.out.println("it's the thing i really want to do");
}
}
public class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
@Override
public void doRequst() {
System.out.println("before do the real thing");
subject.doRequst();
System.out.println("after do the real thing");
}
}
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy(new RealSubject());
proxy.doRequst();
}
}
/**
before do the real thing
it's the thing i really want to do
after do the real thing
**/
这种实现方式即常说的静态代理,有几个方面的约束:
1 代理对象和目标对象需要实现共同的接口,接口有变动,目标对象和代理对象都需要维护。
2 想要代理其他的目标对象,需要新增代理类。
三 动态代理
先看java实现动态代理的几个主要角色
1 Proxy :java.lang.reflect.Proxy,jdk api提供的代理类的主类,该类提供方法动态生成代理类,生成的时候需要指定一组接口(即代理类和目标对象要实现哪些接口)
public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, final InvocationHandler var2) throws IllegalArgumentException
/**
提供了这个静态方法用于动态生成代理类
var0: 目标对象的类加载器
var1: 代理类要实现哪些接口,即目标对象实现的接口
var2: 处理器,代理类具体要做什么写在处理器中
**/
2 InvocationHandler :java.lang.reflect.InvocationHandler
/**
@param proxy the proxy instance that the method was invoked on
代理对象,执行invoke的时候其实是在替这个proxy执行
@param method the {@code Method} instance corresponding to
the interface method invoked on the proxy instance. The declaring
class of the {@code Method} object will be the interface that
the method was declared in, which may be a superinterface of the
proxy interface that the proxy class inherits the method through.
目标对象要执行的方法
@param args an array of objects containing the values of the
arguments passed in the method invocation on the proxy instance,
or {@code null} if interface method takes no arguments.
Arguments of primitive types are wrapped in instances of the
appropriate primitive wrapper class, such as
{@code java.lang.Integer} or {@code java.lang.Boolean}.
执行方法需要的参数
**/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
java动态代理实例
public interface Subject {
void doRequest();
}
public class RealSubject1 implements Subject {
@Override
public void doRequest() {
System.out.println("RealSubject1 want to sing");
}
}
public class RealSubject2 implements Subject {
@Override
public void doRequest() {
System.out.println("RealSubject2 want to dance");
}
}
public class RealInvocationHandler implements InvocationHandler {
private Object subject;
public RealInvocationHandler(Object subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before process");
Object result = method.invoke(subject,args);
System.out.println("after process");
return result;
}
}
public class Client {
public static void main(String[] args) {
Subject realSubject1 = new RealSubject1();
InvocationHandler handler1 = new RealInvocationHandler(realSubject1);
Subject subject1 = (Subject) Proxy.newProxyInstance(realSubject1.getClass().getClassLoader(),realSubject1.getClass().getInterfaces(),handler1);
subject1.doRequest();
System.out.println("-----------------------");
Subject realSubject2 = new RealSubject2();
InvocationHandler handler2 = new RealInvocationHandler(realSubject2);
Subject subject2 = (Subject)Proxy.newProxyInstance(realSubject2.getClass().getClassLoader(),realSubject2.getClass().getInterfaces(),handler2);
subject2.doRequest();
}
}
/**
before process
RealSubject1 want to sing
after process
-----------------------
before process
RealSubject2 want to dance
after process
**/
与静态代理做个比较:
不需要挨个写代理类,想代理其他的,动态new一个代理类
相关源码解析
Proxy.newProxyInstance生成的代理具备什么以及为什么可以转换成目标对象
protected InvocationHandler h;
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 校验handler
if (h == null) {
throw new NullPointerException();
}
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Proxy维护了一个proxyClassCache,如果想要的代理类已经有实现了指定接口的loader定义好了,直接返回cache的备份
* 否则,通过ProxyClassFactory 生成一个代理类,实现指定的intfs
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
//获取构造函数,将传进来的h赋给proxy内部持有的Invokerhanler对象
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
return newInstance(cons, ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}
所以,Proxy生成的代理对象具备一个invokehandler对象的引用;并且实现了目标对象实现的接口,因为可以转换为目标对象的抽象
InvokeHandler为什么可以完成目标对象方法的执行
如上述例子中目标对象RealSubject1要执行doRequest方法,Proxy生成的代理类也会实现这个方法,大概如下:
public final void doRequest()
{
//这个会调用invokehandler的invoke方法,这里的h即是父类Proxy的h,通过newProxyInstance传进来的
try {
this.h.invoke(this, m3, null);
return;
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
有了InvocationHandler 可以使Proxy从具体的代码逻辑抽离出来,更方便统一的生成代理类。
后续todo:
Proxy生成的代理对象的具体剖析
method.invoke具体做了什么
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。