dubbo版本
- dubbo版本2.6.7
Protocol
-
Protocol
层主要包含Protocol
、Filter
、ExporterListener
、InvokerListener
。Protocol层
是RPC的核心调用层,具体的RPC协议都可以通过Protocol
扩展。Protocol
接口是入口,主要用来封装Exporter和Invoker的方法,Protocol#export
将服务暴露的处理过程,Invoker标识服务远程代理对象/** * Protocol. (API/SPI, Singleton, ThreadSafe) */ @SPI("dubbo") public interface Protocol { /** *当用户没有配置端口时获取默认端口 * * @return default port */ int getDefaultPort(); /** * 暴露远程服务: <br> * 1. 协议在接收请求时,应记录请求来源方地址信息: * RpcContext.getContext().setRemoteAddress();<br> * 2. export() 必须是幂等的,也就是暴露同一个URL的Invoker两次,和暴露一次没有区别<br> * 3. 传入的Invoker由框架实现并传入,协议不需要关心<br> * * @param <T> 服务类型 * @param invoker 服务调用者 * @return 暴露服务的引用,用于之后取消暴露 * @throws RpcException 当暴露服务出错时抛出,比如端口已占用 */ @Adaptive <T> Exporter<T> export(Invoker<T> invoker) throws RpcException; /** * 引用远程服务: <br> * 1. 当用户调用refer()所返回的Invoker对象的invoke()方法时,协议需相应执行同URL远端export()传入的Invoker对象的invoke()方法<br> * 2. 返回的Invoker由协议实现,协议通常需要在此Invoker中发送远程请求 <br> * 3. 当url中有设置check=false时,连接失败不能抛出异常,并内部自动恢复 * * @param <T> 服务的类型 * @param type 服务的类 * @param url 远程服务的URL地址 * @return invoker 服务的本地代理 * @throws RpcException 当连接服务提供方失败时抛出 */ @Adaptive <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException; /** * 销毁协议: <br> * 1. 取消该协议所有已经暴露和引用的服务<br> * 2. 释放协议所占用的所有资源,比如连接和端口. <br> * 3. 协议在释放后,依然能暴露和引用新的服务 */ void destroy(); }
-
AbstractProtocol代码
public abstract class AbstractProtocol implements Protocol { protected final Logger logger = LoggerFactory.getLogger(getClass()); //服务暴露者集合 protected final Map<String, Exporter<?>> exporterMap = new ConcurrentHashMap<String, Exporter<?>>(); //TODO SOFEREFENCE 服务引用者集合 protected final Set<Invoker<?>> invokers = new ConcurrentHashSet<Invoker<?>>(); //获取ServiceKey:group0/com.alibaba.dubbo.demo.DemoService:1.0.0:20882 // group+"/"+serviceName+":"+serviceVersion+":"+port protected static String serviceKey(URL url) { int port = url.getParameter(Constants.BIND_PORT_KEY, url.getPort()); return serviceKey(port, url.getPath(), url.getParameter(Constants.VERSION_KEY), url.getParameter(Constants.GROUP_KEY)); } ...省略... }
-
Protocol适配器代码
/* * Decompiled with CFR. * * Could not load the following classes: * com.alibaba.dubbo.common.URL * com.alibaba.dubbo.common.extension.ExtensionLoader * com.alibaba.dubbo.rpc.Exporter * com.alibaba.dubbo.rpc.Invoker * com.alibaba.dubbo.rpc.RpcException */ package com.alibaba.dubbo.rpc; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.extension.ExtensionLoader; import com.alibaba.dubbo.rpc.Exporter; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Protocol; import com.alibaba.dubbo.rpc.RpcException; public class Protocol$Adaptive implements Protocol { @Override public void destroy() { throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); } @Override public int getDefaultPort() { throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); } public Invoker refer(Class clazz, URL uRL) throws RpcException { String string; if (uRL == null) { throw new IllegalArgumentException("url == null"); } URL uRL2 = uRL; String string2 = string = uRL2.getProtocol() == null ? "dubbo" : uRL2.getProtocol(); if (string == null) { throw new IllegalStateException(new StringBuffer().append("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(").append(uRL2.toString()).append(") use keys([protocol])").toString()); } Protocol protocol = (Protocol) ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(string); return protocol.refer(clazz, uRL); } public Exporter export(Invoker invoker) throws RpcException { String string; if (invoker == null) { throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null"); } if (invoker.getUrl() == null) { throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null"); } URL uRL = invoker.getUrl(); String string2 = string = uRL.getProtocol() == null ? "dubbo" : uRL.getProtocol(); if (string == null) { throw new IllegalStateException(new StringBuffer().append("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(").append(uRL.toString()).append(") use keys([protocol])").toString()); } Protocol protocol = (Protocol) ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(string); return protocol.export(invoker); } }
DubboProtocol
-
Dubbo协议在客户端和服务端之间是通过TCP长连接通信的,默认情况下只会维护一个长连接,但是如果在引用服务的时候在消费方(或服务提供方)配置了连接数(
connections
配置),那么Dubbo会为配置的那个service单独维护一个连接集合。而没有配置连接的则统一共享一个TCP连接。<dubbo:reference interface="com.foo.BarService" connections="10" /> <dubbo:service interface="com.foo.BarService" connections="10" /> 都配置以<dubbo:reference/>优先
-
DubboProtocol#export
:就是启动服务端端口public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { //获取Provider的URL URL url = invoker.getUrl(); // export service. String key = serviceKey(url); DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); exporterMap.put(key, exporter); //export an stub service for dispatching event Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT); Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false); if (isStubSupportEvent && !isCallbackservice) { String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY); if (stubServiceMethods == null || stubServiceMethods.length() == 0) { if (logger.isWarnEnabled()) { logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) + "], has set stubproxy support event ,but no stub methods founded.")); } } else { stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods); } } openServer(url); optimizeSerialization(url); return exporter; }
RegistryProtocol
-
RegistryProtocol#export
:服务暴露@Override public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException { //export invoker 打开端口,将服务存储到map中 final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker); //获取注册中心URL //zookeeper://dubbo-zookeeper:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&export=dubbo%3A%2F%2F10.0.75.1%3A20882%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bean.name%3Dcom.alibaba.dubbo.demo.DemoService%26bind.ip%3D10.0.75.1%26bind.port%3D20882%26dubbo%3D2.0.2%26generic%3Dfalse%26group%3Dgroup0%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D67364%26qos.port%3D22223%26revision%3D1.0.0%26side%3Dprovider%26timestamp%3D1626093287774%26version%3D1.0.0&pid=67364&qos.port=22223×tamp=1626093287757 URL registryUrl = getRegistryUrl(originInvoker); //registry provider 根据 URL 加载 Registry 实现类,比如 ZookeeperRegistry final Registry registry = getRegistry(originInvoker); //获取已注册的服务提供者 URL dubbo://10.0.75.1:20882/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bean.name=com.alibaba.dubbo.demo.DemoService&dubbo=2.0.2&generic=false&group=group0&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=67488&revision=1.0.0&side=provider×tamp=1626093385765&version=1.0.0 final URL registeredProviderUrl = getRegisteredProviderUrl(originInvoker); //to judge to delay publish whether or not 获取register参数,判断是否是延迟发布 boolean register = registeredProviderUrl.getParameter("register", true); // 向服务提供者与消费者注册表中注册服务提供者 ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl); // 根据 register 的值决定是否注册服务 if (register) { // 向注册中心注册服务元数据 register(registryUrl, registeredProviderUrl); ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true); } // Subscribe the override data 订阅override数据 // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call the same service. Because the subscribed is cached key with the name of the service, it causes the subscription information to cover. //provider://10.0.75.1:20882/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bean.name=com.alibaba.dubbo.demo.DemoService&category=configurators&check=false&dubbo=2.0.2&generic=false&group=group0&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=67488&revision=1.0.0&side=provider×tamp=1626093385765&version=1.0.0 final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registeredProviderUrl); //创建监听器 final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker); overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener); // 向注册中心进行订阅 override 数据 registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); //Ensure that a new exporter instance is returned every time export // 创建并返回 DestroyableExporter return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl); }
-
RegistryProtocol#doLocalExport
委托DubboProtocol
进行导出private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) { //dubbo://10.0.75.1:20882/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bean.name=com.alibaba.dubbo.demo.DemoService&bind.ip=10.0.75.1&bind.port=20882&dubbo=2.0.2&generic=false&group=group0&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=73868&qos.port=22223&revision=1.0.0&side=provider×tamp=1626098331163&version=1.0.0 String key = getCacheKey(originInvoker); ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key); if (exporter == null) { synchronized (bounds) { exporter = (ExporterChangeableWrapper<T>) bounds.get(key); if (exporter == null) { final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker)); //默认委托DubboProtocol进行服务暴露 exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker); bounds.put(key, exporter); } } } return exporter; }
-
RegistryProtocol#refer
:服务引用public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { //设置注册中心协议 url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY); //创建具体注册中心实例 Registry registry = registryFactory.getRegistry(url); if (RegistryService.class.equals(type)) { return proxyFactory.getInvoker((T) registry, type, url); } // group="a,b" or group="*" 多分组结果聚合 Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY)); String group = qs.get(Constants.GROUP_KEY); if (group != null && group.length() > 0) { if ((Constants.COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) { return doRefer(getMergeableCluster(), registry, type, url); } } //处理订阅数据并通过Cluster合并多个Invoker return doRefer(cluster, registry, type, url); }
-
RegistryProtocol#doRefer
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); // all attributes of REFER_KEY Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters()); URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters); if (!Constants.ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(Constants.REGISTER_KEY, true)) { URL registeredConsumerUrl = getRegisteredConsumerUrl(subscribeUrl, url); //注册消费信息到注册中心 registry.register(registeredConsumerUrl); directory.setRegisteredConsumerUrl(registeredConsumerUrl); } //订阅服务提供者、路由和动态配置 directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY + "," + Constants.CONFIGURATORS_CATEGORY + "," + Constants.ROUTERS_CATEGORY)); //通过Cluster合并invokers Invoker invoker = cluster.join(directory); ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory); return invoker; }