dubbo远程调用模块,围绕着Invoker展开,调用方由DubboInvoker实现Invoker接口,并持有远程通讯的客户端。发送Invocation到服务端,服务端处理后,把结果返回。DubboInvoker包装为RpcResult,这是最里层做的事情。外层DubboInvoker还由ProtocolFilterWrapper进行包装,生成一个调用链;再由ProtocolListenerWrapper包装,增加监听;最后通过JavassistProxyFactory生成代理对象。实现方由JavassistProxyFactory生成Invoker,里层是由Wrapper包装的AbstractProxyInvoker实例。接下来外层由ProtocolFilterWrapper进行包装,生成一个调用链;再由ProtocolListenerWrapper包装,增加监听;最后通过DubboExporter对象持有该Invoker。
过程如下图:(看不清可在新页签查看)
接下来我们具体分析其实现过程的源码,首先看下整个模块的类图情况,如下图(看不清可在新页签查看):
类图中,主要关注与Invoker、Filter、ProxyFactory、Protocol这几个接口相关的实现类。服务端的入口在ServiceConfig的doExportUrlsFor1Protocol方法中。先通过“Invoker<?> invoker = proxyFactory.getInvoker”JavassistProxyFactory获取Invoker;
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper类不能正确处理带$的类名
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
获取的包装后的Inovker再通过“Exporter<?> exporter = protocol.export(invoker)”代码获取DubboExporter。ProtocolListenerWrapper和ProtocolFilterWrapper在通过SPI获取Protocol的时候依次包装Protocol类,ProtocolListenerWrapper代码如下,会去生成一个ListenerExporterWrapper增加相应的监听。
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
return new ListenerExporterWrapper<T>(protocol.export(invoker),
//spi获取所有可用的ExporterListener监听
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
.getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}
之后在ProtocolFilterWrapper生成调用链
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
//buildInvokerChain生成调用链
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
//获取服务端的过虑Filter
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
//循环Filters,串成一条链
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
public Class<T> getInterface() {
return invoker.getInterface();
}
public URL getUrl() {
return invoker.getUrl();
}
public boolean isAvailable() {
return invoker.isAvailable();
}
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
在DubboProtocol.export方法里,封装为一个DubboExporter
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl();
// export service.
String key = serviceKey(url);
//封装为一个DubboExporter
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
exporterMap.put(key, exporter);
//省略很多代码。。。
至此,服务端的Invoker就完成了,接下来看客户端的Invoker。在ReferenceConfig.createProxy作为创建代理对象的入口。
private T createProxy(Map<String, String> map) {
//省略很多代码
if (urls.size() == 1) {
//会调用DubboProtocol.refer去获取DubboInvoker
invoker = refprotocol.refer(interfaceClass, urls.get(0));
}//省略很多代码
}
这里的protocol通过SPI获取时,会有ProtocolListenerWrapper和ProtocolFilterWrapper包装,包装过程跟服务端的类似,这里不在赘述。主要看下DubboProtocol是如何构建DubboInvoker的。
public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
// create rpc invoker.
DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
invokers.add(invoker);
return invoker;
}
这里会去创建DubboInvoker对象,在创建前会先去获取与服务端连接用的client。
private ExchangeClient[] getClients(URL url) {
//是否共享连接
boolean service_share_connect = false;
int connections = url.getParameter(Constants.CONNECTIONS_KEY, 0);
//如果connections不配置,则共享连接,否则每服务每连接
if (connections == 0) {
service_share_connect = true;
connections = 1;
}
ExchangeClient[] clients = new ExchangeClient[connections];
for (int i = 0; i < clients.length; i++) {
if (service_share_connect) {
clients[i] = getSharedClient(url);
} else {
clients[i] = initClient(url);
}
}
return clients;
}
拿到客户端连接后,DubboInvoker就能通过客户端发送Invocation,到服务端处理后返回结果包装为RPCResult对象。
返回的DubboInvoker再经由前面说的两层包装后,会通过JavassistProxyFactory.getProxy获取其代理对象。
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
至此,客户端的Invoker也分析完了。这里需要说一下,我们在@Reference或配置文件里配置的<dubbo:reference>获取的bean,就是这里返回的代理。通过这个代理,去与服务端进行连接,处理,然后客户端解析返回结果。这样,我们对dubbo的Rpc调用的invoker过程就能比较熟悉了。