1.简介
Provide a surrogate or placeholder for another object to control access to it.为一个对象提供一种代理以控制对该对象的访问
---《Design Patterns: Elements of Reusable Object-Oriented Software设计模式-可复用的面向对象软件元素》
代理模式属于结构型设计模式:代理类和真实类实现同一个接口,代理类持有真实类引用,通过代理对象调用真实对象。类图如下所示:
proxy.png
-
代理模式与现实场景下的代理服务器类似,客户端无法直接访问目标服务器或不便于访问,通过代理服务器中转,达到访问控制目的。类图中客户端针对抽象主题角色进行编程,增加和更换代理类无须修改旧代码,符合开闭原则,达到降低代码解耦或扩展目标对象功能等目的。
-
代理模式分类
-- 静态代理:自行编写代理类,即程序运行前就已经存在代理类的字节码文件;
-- 动态代理:代理类在程序运行期间由JVM根据反射等机制动态的生成,不存在代理类的字节码文件
2.静态代理实现
/**
* 被代理类接口声明
*/
public interface ISubject {
void request();
}
/**
* 定义被代理类
*/
public class SubjectImpl implements ISubject {
@Override
public void request() {
Log.d("SubjectImpl", "被代理类");
}
}
/**
* 定义代理类
*/
public class Proxy implements ISubject {
private ISubject subject;
public Proxy(ISubject subject) {
this.subject = subject;
}
@Override
public void request() {
subject.request();
}
}
// 客户端调用
ISubject proxy = new Proxy(new SubjectImpl());
proxy.request();
3.动态代理实现
- 这里通过JDK InvocationHandler实现动态代理,当然也有其它实现方式
public class DynamicProxy implements InvocationHandler {
private Object proxyObject;
// 传入被代理类作为参数,生成代理对象。将代理对象与此InvocationHandler关联,代理对象调用代理方法时将调用InvocationHandler#invoke()
public <T> T newProxyInstance(Object proxyObject) {
this.proxyObject = proxyObject;
return (T) Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(),
proxyObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(proxyObject, args);
// doing somthing else.
return result;
}
}
// 客户端调用,复用前面静态代理中定义的接口和被代理类
DynamicProxy dynamicProxy = new DynamicProxy();
ISubject proxy = dynamicProxy.newProxyInstance(new SubjectImpl());
proxy.request();
-
Proxy#newProxyInstance()参数说明
ClassLoader loader:指定产生代理对象的类加载器,与传入的proxyObject相同的类加载器
Class<?>[] interfaces:指定目标对象的实现接口,即要给目标对象提供一组调用接口
InvocationHandler h:指定关联的InvocationHandler对象,当代理对象proxy调用方法时能关联到invoke()方法 -
注意
newProxyInstance()方法返回值和invoke(Object proxy, ...)方法的第一个参数是真正生成的代理对象。
自动生成的代理对象实现了ISubject接口,通过proxy.request()调用时,方法的内部实现将调用InvocationHandler#invoke()方法并传递通过反射获取的方法名、参数等,最终在InvocationHandler#invoke()方法中执行自己的逻辑。 -
动态代理与静态代理相比有如下优点:不用对每个被代理类都手动写一个代理类,所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke),在接口方法数量比较多的时候,可以更灵活处理。
-
通过JDK提供的动态代理方式可以直接创建一个接口的实例,实际业务中可利用此方式做一些特殊操作,如Retrofit网络请求接口的实现(笔者不认为Retrofit使用了代理模式,只是使用了InvocationHandler的特性构造网络请求参数):
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance( // 通过JDK动态代理的方式生成网络请求接口的实例类
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
Platform platform = Platform.get();
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args); // 解析请求接口的注解和方法参数构造请求参数,生成OkHttp call
}
});
}
- 通过动态代理方式也能实现如下调用:类似接口回调,调用系统接口时传入动态代理类,底层可反过来通过此代理类控制上层逻辑调用
private void init(Context context) {
try {
Class<?> cls = Class.forName("com.me.test.MyManager"); // Framework层提供管理类和接口
Class callbackCls = Class.forName("com.me.test.MyManager$IMyCallback");
Constructor constructorMyManager = cls.getConstructor(new Class[] {Context.class, callbackCls});
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
Object objectCallback = Proxy.newProxyInstance(HostAbility.class.getClassLoader(),
new Class[] {callbackCls}, myInvocationHandler); // APK中完成接口实例化
Object myManager = constructorMyManager.newInstance(new Object[] {context, objectCallback}); // 将生成的接口传给系统层
RealManager realManager = (RealManager) myManager; // apk可调用系统提供的管理类达到一定控制,系统被调用后也可控制触发apk相关逻辑在InvocationHandler中
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | InstantiationException e) {
Logger.e(TAG, "exception in reflecting callback");
}
}
private class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// checking
if (args == null || args.length < LENGTH) {
Logger.e(TAG, "unexpected callback!");
return null;
}
// 获取参数
long p1 = ((Long) args[0]);
int p2 = ((Integer) args[1]);
int p3 = ((Integer) args[2]);
// doing something 由系统在Framework层调用接口后回调到APK中执行,达到由系统层控制上层业务
return null;
}
}
参考
refactoringguru-代理模式
从Retrofit看懂动态代理模式
一定能看懂的 Retrofit 最详细的源码解析
深入理解Retrofit动态代理
枚举、动态代理的原理
网友评论