本文已受权公众号「玉刚说」独家发布java
这里的服务指的是接口API,在代码解耦中,有一种很是重要的方法就是“面向接口编程”,面向接口编程使得协做的模块之间只须要关注接口API,而无需关注API的具体实现。一套好的面向接口编程架构应该至少包含两个方面:简洁通用的接口定义,以及无迹可寻的接口实现。本文介绍的是基于动态代理实现的服务框架,做用场景能够是APP模块化开发或者SDK开发。编程
Java的代理模式能够分红静态代理和动态代理。缓存
静态代理模式很简单,它有三部分组成:接口、委托类、代理类。代理类直接持有委托类的实例,代理类实现了接口里面的方法,没有方法的执行内部直接经过调用委托类实例对应的方法执行。安全
动态代理比静态代理来的更加方便些,固然其本质也是同样的。看过动态代理源码以后能够简单的总结一下:动态代理在运行时生成代理类的字节码,从字节码中建立出代理类的实例,对其全部的方法调用都转发到 invocation handler 的 invoke 方法,在 invoke 方法中执行额外的逻辑。bash
下面,咱们简单从代码层面来回顾一下动态代理的原理。多线程
接口定义架构
public interface Interface {
void doSomething();
}
复制代码
动态代理调用app
Interface anInterface = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
复制代码
动态代理生成的字节码框架
跟踪动态代理源码,能够很清晰的看到其动态建立 proxy 类的过程。这里我简单作了一个实验,我将动态生成的字节码保存到文件中,再反编译读取出来。异步
// 获取字节码再保存到文件中
String proxyName = "$Proxy0";
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName,
new Class[]{Interface.class});
saveToFile(proxyClassFile);
// 经过 JD_GUI 工具读取 $Proxy0.class
public final class $Proxy0 extends Proxy implements Interface
{
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void doSomething()
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.xud.proxy.principle.Interface").getMethod("doSomething", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
复制代码
从生成的代理类能够很是清晰的看到,对代理类中 doSomeThing() 方法的调用最终会回调 InvocationHandler.invoke() 方法。
阅读过 Retrofit 源码的同窗必定对它面向接口的服务使用方式赞叹不已,Retrofit 也是基于动态代理来实现如此优雅的方式的,本文介绍的方式跟 Retrofit 的方式也有相似之处。不过, Retrofit 的动态代理是没有委托类的,咱们只负责定义接口。
假设目前有个接口叫作 AuthService, 咱们先来看看这个接口的使用方式,从而对这种方式有个初步的认识。
接口定义:
public interface AuthService extends Service {
AbortableFuture<String> login(LoginInfo var1);
void logout();
}
复制代码
接口的使用:
AuthService authService = ServiceClient.getService(AuthService.class);
authService.login(loginInfo).setCallback(new RequestCallback() {
@Override
public void onSuccess(Object var1) {
}
@Override
public void onFailed(int var1) {
}
@Override
public void onException(Throwable var1) {
}
});
复制代码
接口通讯须要支持三种模式:
针对这三种状况,定义了如下几个接口,用以处理接口数据返回:
RequestCallback 数据异步回调接口
public interface RequestCallback<T> {
void onSuccess(T var1);
void onFailed(int var1);
void onException(Throwable var1);
}
复制代码
RequestCallbackWrapper 简化后的数据回调接口
public abstract class RequestCallbackWrapper<T> implements RequestCallback<T> {
public RequestCallbackWrapper() {
}
public abstract void onResult(int var1, T var2, Throwable var3);
public void onSuccess(T var1) {
this.onResult(200, var1, (Throwable)null);
}
public void onFailed(int var1) {
this.onResult(var1, (Object)null, (Throwable)null);
}
public void onException(Throwable var1) {
this.onResult(1000, (Object)null, var1);
}
}
复制代码
InvocationFuture 正常状况下的回调接口封装
public interface InvocationFuture<T> {
void setCallback(RequestCallback<T> var1);
}
复制代码
AbortableFuture 可中断的回调接口封装
public interface AbortableFuture<T> extends InvocationFuture {
boolean abort();
}
复制代码
有了这几个通用接口时,咱们在定义具体的服务API接口就很是方便了,好比上面已经写过的 AuthService 接口。
ServiceClient
在获取服务的时候,我但愿有个统一的口子,这个口子就是类 ServiceClient. 这个类中有个核心的方法:getService(), 这是获取服务接口的惟一入口。
public class ServiceClient {
private static ServiceCache serviceCache = new ServiceCache();
private static ServiceMethodExcuter excuter = new ServiceMethodExcuter();
public static <T> T getService(Class<T> cls) {
return serviceCache.getService(cls);
}
public static Object excute(ServiceMethodContainer container) {
return excuter.invoke(container);
}
}
复制代码
ServiceCache
ServiceCache主要是对服务进行缓存,避免每次获取时候重复性建立。
public class ServiceCache {
private final Map<Class<?>, Object> caches = new HashMap();
public ServiceCache() {
}
public final <T> T getService(Class<T> cls) {
if (!cls.isInterface()) {
throw new IllegalArgumentException("only accept interface: " + cls);
} else {
synchronized (this.caches) {
T hitProxy;
if ((hitProxy = (T) this.caches.get(cls)) == null) {
hitProxy = (T) Proxy.newProxyInstance(cls.getClassLoader(), new Class[]{cls}, new ServiceInvovationHandler());
this.caches.put(cls, hitProxy);
}
return hitProxy;
}
}
}
}
复制代码
在这个类中,咱们看到了动态代理的影子,是的,关键就在于它。因此,这个 cache 缓存的是接口服务的代理类。
ServiceInvovationHandler
接口API方法的调用最终会回调 ServiceInvovationHandler.invoke() 方法,我在这个方法中去具体执行接口方法调用,这个类中的 ServiceMethodContainer 是对 method 和 args 的封装。
public class ServiceInvovationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy: " + proxy.getClass() + ", method:" + method + ", args: " + args);
ServiceMethodContainer methodContainer = new ServiceMethodContainer(method, args);
return ServiceClient.excute(methodContainer);
}
}
public class ServiceMethodContainer {
public Method method;
public Object[] args;
public ServiceMethodContainer() {
}
public ServiceMethodContainer(Method method, Object[] args) {
this.method = method;
this.args = args;
}
public String getMethodDeclarClassName() {
return method.getDeclaringClass().getSimpleName();
}
public String getMethodName() {
return method.getName();
}
}
复制代码
ServiceMethodExcuter
在 invoke 方法中,是经过调用 ServiceClient.excute(methodContainer) 来执行具体方法的。为此,有一个类 ServiceMethodExcuter 专门用来作这个事情了。这个类中,也能够看到服务接口的具体委托类的实现,即 代码中的 AuthServiceImpl。因此,本文这种动态代理是一种标准的代理,它有接口、代理类、委托类,这个跟 Retrofit 的设计是不一样的,下面来具体看代码:
public class ServiceMethodExcuter {
private final Map<String, A> serviceMap = new HashMap<>();
ServiceMethodExcuter() {
System.out.println("Register Service Start");
this.addService(AuthService.class, AuthServiceImpl.class);
this.addService(UserService.class, UserServiceImpl.class);
System.out.println("Register Service End");
}
public final Object invoke(ServiceMethodContainer container) {
ServiceMethodExcuter.A a;
if ((a = this.serviceMap.get(container.getMethodDeclarClassName())) == null) {
return null;
} else {
try {
Object object = a.invoke(container);
return object;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
private void addService(Class<?> interfaceCls, Class<? extends Service> implCls) {
this.serviceMap.put(interfaceCls.getSimpleName(), new ServiceMethodExcuter.A(interfaceCls, implCls));
}
private static class A {
private final Map<String, Method> methodMap = new HashMap<>();
private Service realService;
public A (Class<?> interfaceCls, Class<? extends Service> implCls) {
Method[] methods;
int length = (methods = interfaceCls.getDeclaredMethods()).length;
for (int i = 0; i < length; i++) {
Method method = methods[i];
this.methodMap.put(method.getName(), method);
}
try {
this.realService = (Service) implCls.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public final Object invoke(ServiceMethodContainer container) throws Exception {
return this.methodMap.get(container.getMethodName()).invoke(this.realService, container.args);
}
}
}
复制代码
这个类也是这个架构中最关键的一个类,固然,它也很简洁。这个类核心的只有三点:
以上,就把基本的原理介绍清楚了,使用时,就直接经过 ServiceClient.getService() 来获取服务。
因为篇幅问题,本文只对原理性的东西进行展现,并无把更多细节的处理展现出来。因此如下这些问题是读者在实操过程当中要去考虑的。