Write in front
stay Local exposure of dubbo services In this article, we analyze the local service registration using the injvm protocol when scope="local". Together, we look at the most commonly used method in actual business, that is, remote service exposure. Compared with local exposure, we mainly do the following things:
1: Start the communication server, bind the service port, and prepare to receive the remote request from the service consumer. 2: Register the service port information to the Registration Center for service consumers to obtain service call information.
Let's start now!
stay Local exposure of dubbo services On the basis of this article, it starts from doExportUrlsFor1Protocol. For details, refer to 1.1: doExportUrlsFor1Protocol.
1: Remote burst
The sequence diagram is as follows:
1.1: doExportUrlsFor1Protocol
The source code is as follows:
// com.alibaba.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol class FakeCls { private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) { // ***Construct the url that needs to be exposed, such as: dubbo://192.168.2.107:20826/dongshi.daddy.service.scoperemote.ScopeRemoteService?anyhost=true&application=dongshidaddy -provider&bean. name=dongshi. daddy. service. scoperemote. ScopeRemoteService&bind. ip=192.168.2.107&bind. port=20826&dubbo=2.0.2&generic=false&interface=dongshi. daddy. service. scoperemote. ScopeRemoteService&methods=sayHi&owner=dongshidaddy&pid=63200&side=provider×tamp=1643363026148*** // String scope = url.getParameter(Constants.SCOPE_KEY); // The following only deals with non scope="none" if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) { // scope="local", or scope is not configured. In this case, scope=null, and here it will be true if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) { // Omit local burst logic } // scope="remote", or scope is not configured. In this case, scope=null, and here it will be true if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) { if (logger.isInfoEnabled()) { logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); } if (registryURLs != null && !registryURLs.isEmpty()) { // For example: registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=dongshidaddy -provider&dubbo=2.0.2&owner=dongshidaddy&pid=63200®istry=zookeeper×tamp=1643362790535 // Expose the url of the service that needs to be exposed to all registry addresses for (URL registryURL : registryURLs) { // If you don't know what to do, ignore it first! url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY)); // Get the url of the monitoring center. The monitoring center is also a service provider, which is used to count the service call information, times, time-consuming, etc URL monitorUrl = loadMonitor(registryURL); if (monitorUrl != null) { // Monitor, adding the address of the monitor monitoring center, is actually a service provider url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString()); } if (logger.isInfoEnabled()) { logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL); } // Used by service providers to enable the generation of invoker s using custom proxy classes String proxy = url.getParameter(Constants.PROXY_KEY); if (StringUtils.isNotEmpty(proxy)) { registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy); } // 2022-01-31 17:39:34 // Generate Invoker through ProxyFactory // registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()): add the service address to be exposed to the registry address // , key: after adding export: registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=dongshidaddy -provider&dubbo=2.0.2&export= dubbo://192.168.2.107:20826/dongshi.daddy.service.monitor.DubboMonitorService... // When invoking the invoke method of the returned invoker, the corresponding service implementation class, that is, the specific method of ref, will be called internally // Parameter ref: the specific service implementation Class, that is, the Class finally called. interfaceClass: service interface Class. registryURL: Registry address Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())); // Create DelegateProviderMetaDataInvoker objects that encapsulate Invoker and ServiceConfig DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); // 2022-01-31 15:01:03 Exporter<?> exporter = protocol.export(wrapperInvoker); // private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>(); // Added to the exporters collection. The Exporter is used to obtain the invoker and cancel the disclosure exporters.add(exporter); } } else { // The registered address is N/A. at this time, because the registered center address is not configured, it will not register with the registered center, but still listen to the port and leak the service. It is generally used in the scenario of direct connection of the consumer end // If the service consumer wants to connect directly, it needs to set the url attribute, which can be configured as follows: /* <dubbo:reference id="providerService" interface="dongshi.daddy.service.ProviderService" url="dubbo://192.168.10.119:20880/dongshi.daddy.service.ProviderService"/> */ // The fourth parameter is different from the normal way of registering with the registry. null is passed in here, and the url address of the registry is passed in when registering Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); Exporter<?> exporter = protocol.export(wrapperInvoker); exporters.add(exporter); } } } this.urls.add(url); } }
At 15:01:03 on January 31, 2022, there was a sudden leak after the service was completed Local exposure of dubbo services In the article, we know that Protocol is used Wrapper of Adaptive extension class Therefore, before calling the real Protocol implementation class, the automatically generated Adaptive class and all Wrapper classes will be called first, as shown in the following debug diagram:
The reason for the above calling sequence is to ensure that the service startup information is registered with the registry after the service is started, as shown in the following pseudo code:
class RegistryProtocol { void export() { // Use the DubboProtocol burst service, that is, start netty and listen to the service port new DubboProtocol().export(); // After the service is started, register the service information in the registry registerServerInfo(); } }
Let's take a look at the details in 2: Protocol.
2: Protocol
2.1:ProtocolFilterWrapper
The source code is as follows:
class FakeCls { public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { // It is true when the address of the registry is exposed, that is, registry: / / is true, otherwise it is false. At this time, it is a normal service exposure, and a Filter chain needs to be added if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { // 2022-01-31 16:30:07 return protocol.export(invoker); } // Add a new Filter chain, and then generate a new Filter return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER)); } }
At 16:30:07 on January 31, 2022, the registry protocol burst service is used. Therefore, this method mainly does the following two things:
1: Register service to registry Start local receive remote call service->Register service information to the registration center 2: Burst service
Refer to 2.2:RegistryProtocol for details.
2.2:RegistryProtocol
The source code is as follows:
class FakeCls { public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException { // 2022-01-31 16:58:42 // Burst service, that is, start the corresponding local service port and prepare to receive the request call from the network. Note that the service has not been registered in the registration center at this time final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker); // 2022-02-06 16:46:37 URL registryUrl = getRegistryUrl(originInvoker); // Obtain the registration center object, which encapsulates the relevant operations of registration and deregistration. For example, zk is to establish relevant child nodes at the specified node final Registry registry = getRegistry(originInvoker); // Get service provider address, such as dubbo://192.168.64.1:20826/dongshi.daddy.service.monitor.DubboMonitorService?... final URL registeredProviderUrl = getRegisteredProviderUrl(originInvoker); // Whether to register. It is true normally boolean register = registeredProviderUrl.getParameter("register", true); // 2022-02-07 11:16:00 ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl); // Register service address to registration center if (register) { // 2022-02-07 13:05:06 // Register service address to registration center register(registryUrl, registeredProviderUrl); // Settings already registered ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true); } // Fault tolerant related configuration final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registeredProviderUrl); final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker); overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener); registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); // Ensure that a new Exporter is returned, which will be used when canceling the exposure return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl); } }
At 16:58:42 on January 31, 2022, there was a leak service. Refer to 2.2.1 dolocalexport for details. 2022-02-06 16:46:37 is to obtain the address of the registration center. Because the service needs to be registered with the registration center, we start to obtain the address of the registration center here. For details, refer to 2.2.2:getRegistryUrl. At 11:16:00 on February 7, 2022, the service is registered in the local registry. Refer to 4:ProviderConsumerRegTable for details. 2022-02-07 13:05:06 is the registration service address to the registration center. For details, please refer to 2.2.3:register.
2.2.1:doLocalExport
This method only starts the service locally and does not register the service with the registry.
The source code is as follows:
class FakeCls { private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) { // 2022-01-31 17:33:00 String key = getCacheKey(originInvoker); // private final Map<String, ExporterChangeableWrapper<?>> bounds = new ConcurrentHashMap<String, ExporterChangeableWrapper<?>> (); Get from the bounds cache ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key); if (exporter == null) { // upper 🔒 synchronized (bounds) { // 2022-02-01 11:31:59 exporter = (ExporterChangeableWrapper<T>) bounds.get(key); // Still not in cache if (exporter == null) { // Encapsulating the invokerdelegate object is mainly to add the getInvoker method, as follows: /* public Invoker<T> getInvoker() { // Recursive acquisition. The invoker attribute may be invokerdelegate if (invoker instanceof InvokerDelegete) { return ((InvokerDelegete<T>) invoker).getInvoker(); } else { return invoker; } } */ // getProviderUrl(originInvoker): get the service exposure address, such as dubbo://192.168.2.107:20826/dongshi.daddy.service.monitor.DubboMonitorService... final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker)); // 2022-02-01 17:11:26 exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker); bounds.put(key, exporter); } } } return exporter; } }
At 17:33:00 on January 31, 2022, the cache key of bounds is obtained. Refer to 2.2.1.1:getCacheKey for details. It was executed at 11:31:59 on February 1, 2022 DCL check , prevent the conditions for entering synchronization from changing. Protocol at 17:11:26 on February 1, 2022 Export (invokerdelegate) let's analyze, where protocol is Protocol$Adaptive, which is Local exposure of dubbo services In this article, we analyze the dynamically generated code of Protocol$Adaptive as follows:
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol { 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!"); } 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 com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException { if (arg1 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg1; String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); if (extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); return extension.refer(arg0, arg1); } public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException { if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null"); com.alibaba.dubbo.common.URL url = arg0.getUrl(); String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); if (extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); return extension.export(arg0); } }
Note the code string extname = (URL. Getprotocol() = = null) in the export method? "dubbo" : url. getProtocol());, Obtain the target extension name according to the protocol. At this time, debug can see the results as follows:
The result is dubbo, think again Wrapper Therefore, the final calling sequence is protocoladaptive - > protocollistenerwrapper - > potocolfilterwrapper - > dubboprotocol. For the specific calling process, refer to 3:DubboProtocol.
2.2.1.1:getCacheKey
The source code is as follows:
class FakeCls { private String getCacheKey(final Invoker<?> originInvoker) { // 2022-01-31 17:38:19 // Get service provider address URL providerUrl = getProviderUrl(originInvoker); // Delete dynamic, enabled, and then convert it into a string as the cache key. The result is as follows: // dubbo://192.168.2.107:20826/dongshi.daddy.service.monitor.DubboMonitorService... String key = providerUrl.removeParameters("dynamic", "enabled").toFullString(); return key; } }
At 17:38:19 on January 31, 2022, the URL of the service provider is obtained. The source code is as follows:
class FakeCls { private URL getProviderUrl(final Invoker<?> origininvoker) { // The value has been set at 17:39:34 on 2022-01-31, so it can be obtained directly here // For example: registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?...&export= // The result obtained is: Dubbo% 3A% 2F% 2f192 168.2.107%3A20826%2Fdongshi. daddy. service. monitor. DubboMonitorService String export = origininvoker.getUrl().getParameterAndDecoded(Constants.EXPORT_KEY); // There must be export here, or Java. Is thrown Lang.illegalargumentexception exception if (export == null || export.length() == 0) { throw new IllegalArgumentException("The registry export url is null! registry: " + origininvoker.getUrl()); } // Turn to com alibaba. dubbo. common. URL object URL providerUrl = URL.valueOf(export); return providerUrl; } }
2.2.2:getRegistryUrl
The source code is as follows:
class FakeCls { // com.alibaba.dubbo.registry.integration.RegistryProtocol.getRegistryUrl private URL getRegistryUrl(Invoker<?> originInvoker) { // Get the address of the registration center directly, such as: registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?... URL registryUrl = originInvoker.getUrl(); // If it is "public static final string registry_protocol =" Registry " Protocol, i.e. registry:// if (Constants.REGISTRY_PROTOCOL.equals(registryUrl.getProtocol())) { // Get the value of the registry parameter as the new protocol name. If I use zk locally, yes registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?...®istry=zookeeper... // The result is zookeeper String protocol = registryUrl.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_DIRECTORY); // Use zookeeper as the new protocol name, registry://127.0.0.1:2181... -> zookeeper://127.0.0.1:2181... registryUrl = registryUrl.setProtocol(protocol).removeParameter(Constants.REGISTRY_KEY); } // The results are as follows: zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?... return registryUrl; } }
2.2.3:register
The source code is as follows:
class FakeCls { // com.alibaba.dubbo.registry.integration.RegistryProtocol.register public void register(URL registryUrl, URL registedProviderUrl) { // 2022-02-07 14:17:03 Registry registry = registryFactory.getRegistry(registryUrl); // 2022-02-07 15:51:34 // If you use zk as the registration center, you can get com alibaba. dubbo. registry. zookeeper. ZookeeperRegistry registry.register(registedProviderUrl); } }
At 14:17:03 on February 7, 2022, the Registry is obtained through RegistryFactory, where RegistryFactory is a self-adaption registryFactory is an automatically generated adaptive extension class RegistryFactory$Adaptive.
The source code of RegistryFactory is as follows:
@SPI("dubbo") public interface RegistryFactory { @Adaptive({"protocol"}) Registry getRegistry(URL url); }
The automatically generated code is as follows:
package com.alibaba.dubbo.registry; import com.alibaba.dubbo.common.extension.ExtensionLoader; public class RegistryFactory$Adaptive implements com.alibaba.dubbo.registry.RegistryFactory { public com.alibaba.dubbo.registry.Registry getRegistry(com.alibaba.dubbo.common.URL arg0) { if (arg0 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg0; String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.registry.RegistryFactory) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.registry.RegistryFactory extension = (com.alibaba.dubbo.registry.RegistryFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.registry.RegistryFactory.class).getExtension(extName); return extension.getRegistry(arg0); } }
Execute code string extname = (URL. Getprotocol() = = null? "dubbo" : url. getProtocol() );, The result obtained is extName=zookeeper. Which extension class does it correspond to? You can get it from meta-inf \ Dubbo \ internal \ com alibaba. dubbo. registry. Find the answer in the registryfactory file, as follows:
dubbo=com.alibaba.dubbo.registry.dubbo.DubboRegistryFactory multicast=com.alibaba.dubbo.registry.multicast.MulticastRegistryFactory zookeeper=com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistryFactory redis=com.alibaba.dubbo.registry.redis.RedisRegistryFactory
The final obtained extension class is ZookeeperRegistryFactory, and its getRegistry will be called. Because this method is defined in its parent class AbstractRegistryFactory, the final called method is as follows:
class FakeCls { // com.alibaba.dubbo.registry.support.AbstractRegistryFactory.getRegistry public Registry getRegistry(URL url) { // 1: Set the path to com alibaba. dubbo. registry. RegistryService // 2: Set the parameter interface = com alibaba. dubbo. registry. RegistryService // 3: Delete parameter export url = url.setPath(RegistryService.class.getName()) .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName()) .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY); // Cache key, such as zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService String key = url.toServiceString(); LOCK.lock(); try { // Cache fetch Registry registry = REGISTRIES.get(key); // If there is a cache, return directly if (registry != null) { return registry; } // 2022-02-07 14:58:54 registry = createRegistry(url); // You can't get it if (registry == null) { throw new IllegalStateException("Can not create registry " + url); } // Put in cache REGISTRIES.put(key, registry); return registry; } finally { LOCK.unlock(); } } }
At 14:58:54 on February 7, 2022, a Registry is created. For details, refer to 2.2.4:createRegistry. 2022-02-07 15:51:34 is the url of the service provider registered through the Registry of the corresponding registration center. For details, refer to 2.2.5: registering the service address to the registration center.
2.2.4:createRegistry
The source code is as follows:
class FakeCls { // com.alibaba.dubbo.registry.support.AbstractRegistryFactory.createRegistry protected abstract Registry createRegistry(URL url); }
We found that this is an abstract template method, specifically calling com alibaba. dubbo. registry. zookeeper. ZookeeperRegistryFactory. Createregistry. The source code is as follows:
class FakeCls { // com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistryFactory.createRegistry public Registry createRegistry(URL url) { // Return directly from new ZookeeperRegistry return new ZookeeperRegistry(url, zookeeperTransporter); } }
The ZookeeperRegistry constructor is as follows:
class FakeCls { // com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry.ZookeeperRegistry public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) { super(url); if (url.isAnyHost()) { throw new IllegalStateException("registry address == null"); } // dubbo String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT); // /dubbo if (!group.startsWith(Constants.PATH_SEPARATOR)) { group = Constants.PATH_SEPARATOR + group; } this.root = group; // Gets the client object of the operation zk zkClient = zookeeperTransporter.connect(url); // Add state change listener zkClient.addStateListener(new StateListener() { @Override public void stateChanged(int state) { if (state == RECONNECTED) { try { recover(); } catch (Exception e) { logger.error(e.getMessage(), e); } } } }); } }
2.2.5: register the service address to the registration center
Let's take ZookeeperRegistry as an example. The source code is as follows:
class FakeCls { // com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry.doRegister protected void doRegister(URL url) { try { // toUrlPath(url): the zk path to create, such as / Dubbo / Dongshi daddy. service. monitor. DubboMonitorService/providers/dubbo... version%3D0. zero point one one // After execution, the corresponding path is established in zk, the service information is registered in the registration center, and consumers can obtain the information of service providers through the registration center zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true)); } catch (Throwable e) { throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e); } } }
3:DubboProtocol
The source code is as follows:
class FakeCls { public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { // Get the url object, such as dubbo://192.168.2.107:20826/dongshi.daddy.service.monitor.DubboMonitorService... URL url = invoker.getUrl(); // 2022-02-01 18:58:33 String key = serviceKey(url); // exporterMap->new ConcurrentHashMap<String, Exporter<?>> (); A service that stores a burst (local startup service) DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); //zs into map exporterMap.put(key, exporter); /*** Ignore start for now***/ 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); } } /*** Ignore end for now***/ // 2022-02-02 10:10:53 openServer(url); // Initialization sequencer optimizeSerialization(url); return exporter; } }
2022-02-01 18:58:33 is the unique identifier of the generated service. For details, refer to 3.1:serviceKey. 2022-02-02 10:10:53 is the start server. For details, refer to 3.2:openServer.
3.1:serviceKey
The source code is as follows:
class FakeCls { protected static String serviceKey(URL url) { // Get the port to bind, public static final String BIND_PORT_KEY = "bind.port"; // dubbo://192.168.2.107:20826/dongshi.daddy.service.monitor.DubboMonitorService , the result is 20826 int port = url.getParameter(Constants.BIND_PORT_KEY, url.getPort()); // port: 20826, // url.getPath(): dongshi.daddy.service.monitor.DubboMonitorService // url.getParameter(Constants.VERSION_KEY): such as < Dubbo: Service Version = "0.0.11" / >, value is 0.0.11 // url.getParameter(Constants.GROUP_KEY): such as < Dubbo: Service Group = "xxxx" / >, the value is xxxx // 2022-02-01 19:51:29 return serviceKey(port, url.getPath(), url.getParameter(Constants.VERSION_KEY), url.getParameter(Constants.GROUP_KEY)); } }
At 19:51:29 on February 1, 2022, the method com was finally called alibaba. dubbo. rpc. support. ProtocolUtils. The source code of servicekey (int, java.lang.string, java.lang.string, Java. Lang.string) is as follows:
class FakeCls { // com.alibaba.dubbo.rpc.support.ProtocolUtils.serviceKey(int, java.lang.String, java.lang.String, java.lang.String) public static String serviceKey(int port, String serviceName, String serviceVersion, String serviceGroup) { StringBuilder buf = new StringBuilder(); // Group name/ if (serviceGroup != null && serviceGroup.length() > 0) { buf.append(serviceGroup); buf.append("/"); } // Group name / service name buf.append(serviceName); // Group name / Service Name: version number if (serviceVersion != null && serviceVersion.length() > 0 && !"0.0.0".equals(serviceVersion)) { buf.append(":"); buf.append(serviceVersion); } // Group name / Service Name: version number: port number buf.append(":"); buf.append(port); // The result is as follows: XXXX / Dongshi daddy. service. monitor. DubboMonitorService:0.0.11:20826 return buf.toString(); } }
3.2:openServer
The source code is as follows:
class FakeCls { private void openServer(URL url) { // Use the address as the unique identifier, such as 192.168.2.107:20826 String key = url.getAddress(); // The default value is "true", so the default value is "None" boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true); if (isServer) { // Exchange Server represents the Server and is a sub interface of the Server interface // Map<String, ExchangeServer> serverMap = new ConcurrentHashMap<String, ExchangeServer>(); // keyï¼›host:port value: ExchangeServer ExchangeServer server = serverMap.get(key); if (server == null) { // 2022-02-05 20:26:00 serverMap.put(key, createServer(url)); // When there are multiple service s, it will not be empty } else { // Because it indirectly inherited com alibaba. dubbo. common. Resettable interface, so relevant properties can be reset here server.reset(url); } } } }
2022-02-05 at 20:26:00 is to create a Server using the URL and add it to the serverMap. For details, refer to 3.3:createServer.
3.3:createServer
The source code is as follows:
class FakeCls { private ExchangeServer createServer(URL url) { // public static final String CHANNEL_READONLYEVENT_SENT_KEY = "channel.readonly.sent"; // Send READONLY event when the server is shut down // dubbo://192.168.2.107:20826/dongshi.daddy.service.monitor.DubboMonitorService?...&channel.readonly.sent=true&... url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString()); // public static final int DEFAULT_HEARTBEAT = 60 * 1000; // public static final String HEARTBEAT_KEY = "heartbeat"; // Enable heartbeat. The default heartbeat duration is one minute // dubbo://192.168.2.107:20826/dongshi.daddy.service.monitor.DubboMonitorService?...&heartbeat=60000&... url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT)); // public static final String SERVER_KEY = "server"; // public static final String DEFAULT_REMOTING_SERVER = "netty"; // Check whether there is a corresponding named Transporter Dubbo SPI extension class. Transporter is an interface used to operate netty, mina and other frameworks String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER); // Ensure that the corresponding extension class exists if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) throw new RpcException("Unsupported server type: " + str + ", url: " + url); // dubbo codec is used for encoding and decoding, i.e. dubbocount codec url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME); ExchangeServer server; try { // 2022-02-06 12:45:27 server = Exchangers.bind(url, requestHandler); } catch (RemotingException e) { throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e); } // Verify that the client extension class must exist str = url.getParameter(Constants.CLIENT_KEY); if (str != null && str.length() > 0) { Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(); if (!supportedTypes.contains(str)) { throw new RpcException("Unsupported client type: " + str); } } return server; } }
At 12:45:27 on February 6, 2022, the exchange is the owner of the exchange Facade class , which is used to encapsulate the details of the underlying system and simplify the use of users. Finally, exchange Server is returned, which is a sub interface of Server. The definition is as follows:
public interface ExchangeServer extends Server { Collection<ExchangeChannel> getExchangeChannels(); ExchangeChannel getExchangeChannel(InetSocketAddress remoteAddress); }
The log of bind method execution output is as follows:
[2022-02-0613:06:28][INFO ][jpm-AbstractServer-<init>(65)]- [DUBBO] Start NettyServer bind /0.0.0.0:20826, export /192.168.2.107:20826, dubbo version: 2.6.6, current host: 192.168.2.107
It can be seen that the netty service is started and the service port is exposed.
4:ProviderConsumerRegTable
This class is a support class (tool class) for the registration of local service consumers and service providers. In order to the Invoker of service providers and service consumers, it is mainly used for QOS(quality of service), such as offline, statistics, etc. the relevant codes are as follows:
public class ProviderConsumerRegTable { /** * Service provider Invoker collection * key: Service provider URL */ public static ConcurrentHashMap<String, Set<ProviderInvokerWrapper>> providerInvokers = new ConcurrentHashMap<String, Set<ProviderInvokerWrapper>>(); /** * Service consumer Invoker collection * key: Service consumer URL */ public static ConcurrentHashMap<String, Set<ConsumerInvokerWrapper>> consumerInvokers = new ConcurrentHashMap<String, Set<ConsumerInvokerWrapper>>(); // .... Omitting method }
4.1:ProviderInvokerWrapper
The wrapper class of provider invoker mainly adds some additional auxiliary operation and maintenance attributes, such as the attribute isReg marking whether to register. After offline operation, it can be modified to false, indicating that it has been offline. The main attributes are as follows:
class FakeCls { /** * Invoker object */ private Invoker<T> invoker; /** * Original URL */ private URL originUrl; /** * Registry URL */ private URL registryUrl; /** * Service provider URL */ private URL providerUrl; /** * Register */ private volatile boolean isReg; }
4.2:ConsumerInvokerWrapper
The wrapper class of consumer invoker mainly adds some additional attributes, as follows:
class FakeCls { /** * Invoker object */ private Invoker<T> invoker; /** * Original URL */ private URL originUrl; /** * Registry URL */ private URL registryUrl; /** * Consumer URL */ private URL consumerUrl; /** * Registry Directory */ private RegistryDirectory registryDirectory; }