0 文章概述
DUBBO作为RPC领域优秀开源的框架在业界十分流行,本文我们阅读其源码并对其使用到的设计模式进行分析。需要说明的是本文所说的设计模式更加广义,不仅包括标准意义上23种设计模式,还有一些常见经过检验的代码模式例如双重检查锁模式、多线程保护性暂停模式等等。
1 模板方法
模板方法模式定义一个操作中的算法骨架,一般使用抽象类定义算法骨架。抽象类同时定义一些抽象方法,这些抽象方法延迟到子类实现,这样子类不仅遵守了算法骨架约定,也实现了自己的算法。既保证了规约也兼顾灵活性。这就是用抽象构建框架,用实现扩展细节。
DUBBO源码中有一个非常重要的核心概念Invoker,我们可以理解为执行器或者说一个可执行对象,能够根据方法的名称、参数得到相应执行结果,这个特性体现了代理模式我们后面章节再说,本章节我们先分析其中的模板方法模式。
public abstract class AbstractInvoker<T> implements Invoker<T> {
@Override
public Result invoke(Invocation inv) throws RpcException {
RpcInvocation invocation = (RpcInvocation) inv;
invocation.setInvoker(this);
if (attachment != null && attachment.size() > 0) {
invocation.addAttachmentsIfAbsent(attachment);
}
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
if (contextAttachments != null && contextAttachments.size() != 0) {
invocation.addAttachments(contextAttachments);
}
if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) {
invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
}
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
try {
return doInvoke(invocation);
} catch (InvocationTargetException e) {
Throwable te = e.getTargetException();
if (te == null) {
return new RpcResult(e);
} else {
if (te instanceof RpcException) {
((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
}
return new RpcResult(te);
}
} catch (RpcException e) {
if (e.isBiz()) {
return new RpcResult(e);
} else {
throw e;
}
} catch (Throwable e) {
return new RpcResult(e);
}
}
protected abstract Result doInvoke(Invocation invocation) throws Throwable;
}
AbstractInvoker作为抽象父类定义了invoke方法这个方法骨架,并且定义了doInvoke抽象方法供子类扩展,例如子类InjvmInvoker、DubboInvoker各自实现了doInvoke方法。
InjvmInvoker是本地引用,调用时直接从本地暴露生产者容器获取生产者Exporter对象即可。
class InjvmInvoker<T> extends AbstractInvoker<T> {
@Override
public Result doInvoke(Invocation invocation) throws Throwable {
Exporter<?> exporter = InjvmProtocol.getExporter(exporterMap, getUrl());
if (exporter == null) {
throw new RpcException("Service [" + key + "] not found.");
}
RpcContext.getContext().setRemoteAddress(Constants.LOCALHOST_VALUE, 0);
return exporter.getInvoker().invoke(invocation);
}
}
DubboInvoker相对复杂一些,需要考虑同步异步调用方式,配置优先级,远程通信等等。
public class DubboInvoker<T> extends AbstractInvoker<T> {
@Override
protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;
final String methodName = RpcUtils.getMethodName(invocation);
inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
inv.setAttachment(Constants.VERSION_KEY, version);
ExchangeClient currentClient;
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
try {
boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
boolean isAsyncFuture = RpcUtils.isReturnTypeFuture(inv);
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
// 超时时间方法级别配置优先级最高
int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
if (isOneway) {
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent);
RpcContext.getContext().setFuture(null);
return new RpcResult();
} else if (isAsync) {
ResponseFuture future = currentClient.request(inv, timeout);
FutureAdapter<Object> futureAdapter = new FutureAdapter<>(future);
RpcContext.getContext().setFuture(futureAdapter);
Result result;
if (isAsyncFuture) {
result = new AsyncRpcResult(futureAdapter, futureAdapter.getResultFuture(), false);
} else {
result = new SimpleAsyncRpcResult(futureAdapter, futureAdapter.getResultFuture(), false);
}
return result;
} else {
RpcContext.getContext().setFuture(null);
return (Result) currentClient.request(inv, timeout).get();
}
} catch (TimeoutException e) {
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} catch (RemotingException e) {
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
}
2 动态代理
代理模式核心是为一个目标对象提供一个代理,以控制对这个对象的访问,我们可以通过代理对象访问目标对象,这样可以增强目标对象功能。
代理模式分为静态代理与动态代理,动态代理又分为JDK代理和Cglib代理,JDK代理只能代理实现类接口的目标对象,但是Cglib没有这种要求。
2.1 JDK动态代理
动态代理本质是通过生成字节码的方式将代理对象织入目标对象,本文以JDK动态代理为例。
动态代理本质是通过生成字节码的方式将代理对象织入目标对象,本文以JDK动态代理为例。
第一步定义业务方法,即被代理的目标对象:
public interface StudentJDKService {
public void addStudent(String name);
public void updateStudent(String name);
}
public class StudentJDKServiceImpl implements StudentJDKService {
@Override
public void addStudent(String name) {
System.out.println("add student=" + name);
}
@Override
public void updateStudent(String name) {
System.out.println("update student=" + name);
}
}
第二步定义一个事务代理对象:
public class TransactionInvocationHandler implements InvocationHandler {
private Object target;
public TransactionInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------前置通知------");
Object rs = method.invoke(target, args);
System.out.println("------后置通知------");
return rs;
}
}
第三步定义代理工厂:
public class ProxyFactory {
public Object getProxy(Object target, InvocationHandler handler) {
ClassLoader loader = this.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
Object proxy = Proxy.newProxyInstance(loader, interfaces, handler);
return proxy;
}
}
第四步进行测试:
public class ZTest {
public static void main(String[] args) throws Exception {
testSimple();
}
public static void testSimple() {
StudentJDKService target = new StudentJDKServiceImpl();
TransactionInvocationHandler handler = new TransactionInvocationHandler(target);
ProxyFactory proxyFactory = new ProxyFactory();
Object proxy = proxyFactory.getProxy(target, handler);
StudentJDKService studentService = (StudentJDKService) proxy;
studentService.addStudent("JAVA前线");
}
}
ProxyGenerator.generateProxyClass是生成字节码文件核心方法,我们看一看动态字节码到底如何定义:
public class ZTest {
public static void main(String[] args) throws Exception {
createProxyClassFile();
}
public static void createProxyClassFile() {
String name = "Student$Proxy";
byte[] data = ProxyGenerator.generateProxyClass(name, new Class[] { StudentJDKService.class });
FileOutputStream out = null;
try {
String fileName = "c:/test/" + name + ".class";
File file = new File(fileName);
out = new FileOutputStream(file);
out.write(data);
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
if (null != out) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
最终生成字节码文件如下,我们看到代理对象被织入了目标对象:
import com.xpz.dubbo.simple.jdk.StudentJDKService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class Student$Proxy extends Proxy implements StudentJDKService {
private static Method m1;
private static Method m2;
private static Method m4;
private static Method m3;
private static Method m0;
public Student$Proxy(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 error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
} catch (Error | RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void updateStudent(String paramString) {
try {
this.h.invoke(this, m4, new Object[] { paramString });
return;
} catch (Error | RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void addStudent(String paramString) {
try {
this.h.invoke(this, m3, new Object[] { paramString });
return;
} catch (Error | RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return ((Integer)this.h.invoke(this, m0, null)).intValue();
} catch (Error | RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
static {
t