dubboProtocol是dubbo中的核心类,具体实现了暴露服务和引用服务。也就是export方法。
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl();
// export service.
String key = serviceKey(url);
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
exporterMap.put(key, exporter);
// .....
openServer(url);
return exporter;
}
export的方法很简单,上面只保留了核心代码,可以看到首先根据url生成serviceKey,也就是这个invoker的唯一标识,然后放到exportMap中缓存起来。openServer会启动一个socket服务(默认监听20880端口),里面最终会调用createServer方法:
private ExchangeServer createServer(URL url) {
//....
ExchangeServer server;
try {
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
// ....
return server;
}
可以看到server里面放置了一个requestHandler,来处理所有的请求,其实这个handler也是一个dispatcher:
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
Invocation inv = (Invocation) message;
Invoker<?> invoker = getInvoker(channel, inv);
// ....
RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
return invoker.invoke(inv);
}
throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
}
reply就是requestHanlder的核心方法,getInvoker会计算inv的serviceKey,然后从exporter缓存中找到exporter,进而拿到invoker,调用后返回结果。
export方法执行完成后就标志服务端可以接收客户端的请求了,但是还需要向注册中心注册:
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
//export invoker
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
//registry provider
final Registry registry = getRegistry(originInvoker);
final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
registry.register(registedProviderUrl);
// .....
}
这是RegistryProtocol的export方法,可以看到调用getRegistry拿到Registry后,其实Registry是一个代理,调用了远程服务Registry的register方法完成注册。
ok,这就是服务端暴露服务的过程。
再来看客户端引用的过程:从下图中可以看到客户端在通过getBean方法最终会调用createProxy,然后是refer方法:
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
directory.setRegistry(registry);
directory.setProtocol(protocol);
URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, NetUtils.getLocalHost(), 0, type.getName(), directory.getUrl().getParameters());
if (! Constants.ANY_VALUE.equals(url.getServiceInterface())
&& url.getParameter(Constants.REGISTER_KEY, true)) {
registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
Constants.CHECK_KEY, String.valueOf(false)));
}
directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY,
Constants.PROVIDERS_CATEGORY
+ "," + Constants.CONFIGURATORS_CATEGORY
+ "," + Constants.ROUTERS_CATEGORY));
return cluster.join(directory);
}
这是RegistryProtocol的doRefer方法,可以看到是向Registry请求感兴趣的服务地址,Registry返回的每一个url都会被dubboProtocol使用refer封装成一个invoker,最后RegistryProtocol使用cluster把所有的invoker封装成一个invoker(加入了负载均衡的逻辑),也就是代理。
ok,这就是服务暴漏,服务注册,服务发现,服务调用的所有过程了。