dubbo source code - service export

in conclusion

The so-called service export means that the service provider registers the local service to the zk cluster and opens netty to receive consumer requests. We can also think that the dubbo service provider is a netty server

For service export, the following steps will be performed:
1. Perform some verification, parameter value, assignment, etc. (override the same parameter configuration)
2. Obtain all registries and obtain all configured protocols
3. Assemble url objects, Since dubbo is based on the URL to complete the registration, it will first splice and assemble the URL
4. Generate the Invoker object according to the URL and the registry (Registration Center)
5. Wrap the Invoker object, and then perform the real export
5.1 First, it will be based on the service ip and port, open a netty service
5.2 and then convert the url into a zk node, and register, in fact, it is registered to the registry, for example: zookeeper
5.3 monitoring path information (the specific monitoring path here needs to be reconfirmed and learned)

Therefore, we can think that service export is divided into two major steps:
1. Parameter verification, assembly parameters
2. Service exposure to the remote
When exposed to the remote, it will be divided into the following steps
2.1 Open a netty service
2.2 Register to zk

Export source code

The version I am studying is still 2.6, so there will be some differences with the code of 2.7. The source code
exported by the dubbo service can be understood as

com.alibaba.dubbo.config.spring.ServiceBean#onApplicationEvent

Starting with this line of code, after the spring container is started, a ContextRefreshedEvent event will occur. After dubbo listens to the event, it will start to export the service
. For details on how dubbo uses spring extension points to complete initialization, please refer to this blog --> How does dubbo use spring extension points to complete initialization

com.alibaba.dubbo.config.ServiceConfig#export
public synchronized void export() {
    
    
        if (provider != null) {
    
    
            if (export == null) {
    
    
                export = provider.getExport();
            }
            if (delay == null) {
    
    
                delay = provider.getDelay();
            }
        }
        /**
         * 1.判断是否已经导出,如果已经导出,return
         * 2.判断是否是延迟导出
         * 3.如果是非延迟导出,就进行服务导出
         */
        if (export != null && !export) {
    
    
            return;
        }

        if (delay != null && delay > 0) {
    
    
            delayExportExecutor.schedule(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    doExport();
                }
            }, delay, TimeUnit.MILLISECONDS);
        } else {
    
    
            doExport();
        }
    }

In the doExport() method, there will be a series of parameter assignments and verifications. Here I will give a screenshot

Insert picture description here
The doExportUrls here is to export the service

private void doExportUrls() {
    
    
    /**
         * 如果是多注册中心,这里会获取到所有配置的注册中心
         */
    List<URL> registryURLs = loadRegistries(true);
    /**
         * 如果是多个协议,这里会循环多个协议
         */
    for (ProtocolConfig protocolConfig : protocols) {
    
    
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}

doExportUrlsFor1Protocol() In this method, in summary, two things are completed:
1. Assemble and re-splice the URL
2. Perform real service export
In this method, it will be judged according to the scope attribute configured by the service provider. Export to local or remote service
When exporting the service, an Invoker object will be generated according to the service provider, and then the Invoker object will be exported.

Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);

When the protocol.export() method is called, the following call links will be passed in turn

org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper#export
org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper#export
org.apache.dubbo.qos.protocol.QosProtocolWrapper#export
org.apache.dubbo.registry.integration.RegistryProtocol#export

The calling sequence here is related to the spi mechanism of dubbo. What each export does is discussed later. The
core work is in the org.apache.dubbo.registry.integration.RegistryProtocol#export method.

@Override
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
    
    
    //export invoker
    /**
    * 1、导出服务,创建nettyServer
    * 这里是调用的是DubboProtocol的export方法来开启netty服务的
    */
    final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);

    //获取注册中心的URL, zookeeper://ip:port/xxxxx
    URL registryUrl = getRegistryUrl(originInvoker);

    //registry provider
    final Registry registry = getRegistry(originInvoker);
    final URL registeredProviderUrl = getRegisteredProviderUrl(originInvoker);

    //to judge to delay publish whether or not
    boolean register = registeredProviderUrl.getParameter("register", true);

    ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl);

    if (register) {
    
    
        /**
         * 2、这里是真正的服务注册的逻辑
         * registryUrl:是以zookeeper://ip:port
         * registeredProviderUrl:是以协议开头的,dubbo://ip:port
         *
         * 调用FailBackRegistry(这里要看配置的是哪种服务容错策略)
         */
        register(registryUrl, registeredProviderUrl);
        ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
    }

    // Subscribe the override data
    // 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.
    //3、事件监听 待学习补充
    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 instance is returned every time export
    return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registeredProviderUrl);
}

Open netty service

doLocalExport(originInvoker)
In this method, the export method of dubboProtocol will be called through the extension mechanism of spi. In the export method, the netty server will be opened.

The call chain of the following method is like this:

com.alibaba.dubbo.registry.integration.RegistryProtocol#export
	com.alibaba.dubbo.registry.integration.RegistryProtocol#doLocalExport
		com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#export
			com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#openServer
private void openServer(URL url) {
    
    
        // find server.
        String key = url.getAddress();
        //client can export a service which's only for server to invoke
        boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
        if (isServer) {
    
    
            ExchangeServer server = serverMap.get(key);
            if (server == null) {
    
    
                serverMap.put(key, createServer(url));
            } else {
    
    
                // server supports reset, use together with override
                server.reset(url);
            }
        }
    }

The logic behind the createServer() method is not described in this note. We can think that createServer opens the netty server

Registration center registration

In the com.alibaba.dubbo.registry.integration.RegistryProtocol#exportmethod, the above doLocalExport() method will be called first to start the netty server, and then go to the registry to register the service

@SPI("dubbo")
public interface RegistryFactory {
    
    

    @Adaptive({
    
    "protocol"})
    Registry getRegistry(URL url);
}

When obtaining the registry, it is also implemented through the SPI mechanism. The default is dubbo. We take zk as an example. If the registry we configure is zk, then ZookeeperRegistry will be created.

Then in

com.alibaba.dubbo.registry.integration.RegistryProtocol#export
	com.alibaba.dubbo.registry.integration.RegistryProtocol#register

According to the registryUrl to get the current registry factory, if it is zk, then it will call

com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry#doRegister

@Override
    protected void doRegister(URL url) {
    
    
        try {
    
    
            /**
             * 这里的toUrlPath,最终会把路径转换为 dubbo/接口全类名/服务暴露的地址
             * 这里true,表示zk创建的是临时节点
             */
            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);
        }
    }

You can see here, the directly called zkClient.create() method

The principle of dubbo export is basically like this. After the revision of the dubbo official website document, a sequence diagram of service export and service introduction is provided on dubbo official website
Insert picture description here

So the above is the core principle of dubbo service export

Guess you like

Origin blog.csdn.net/CPLASF_/article/details/113794622