美文网首页
Dubbo系列--消费者服务引用《五》

Dubbo系列--消费者服务引用《五》

作者: Teddy_b | 来源:发表于2023-11-28 18:17 被阅读0次

示例代码

Dubbo中的服务调用实例代码

        ReferenceConfig<HelloService> reference = new ReferenceConfig<>();
        reference.setInterface(HelloService.class);
        //reference.setGeneric("true");

        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
        bootstrap.application(new ApplicationConfig("dubbo-demo-api-consumer"))
                .registry(new RegistryConfig("zookeeper://1.2.3.4:32181"))
                .protocol(new ProtocolConfig("dubbo", -1))
                .reference(reference)
                .start();

        HelloService demoService = bootstrap.getCache().get(reference);
        String message = demoService.sayHello("dubbo");
        System.out.println(message);

服务调用示例比较简单

  • 通过ReferenceConfig配置接口信息

  • 配置注册中心地址后,启动服务调用者

  • 通过bootstrap.getCache().get(reference)获取代理实现类,然后通过代理实现类调用接口方法

代理对象

上面主要的一步是获取代理实现类,我们看下代理实现类是怎么创建的呢?

从上面的代码中可以看到是从缓存中获取的代理实现类,可见其在服务调用者启动的过程中就已经创建好了

我们再看一眼启动流程

private synchronized Future startSync() throws IllegalStateException {
           ...
            exportServices();

            // refer services
            referServices();

可以看到在导出服务之后就有一步引用服务

private void referServices() {
        configManager.getReferences().forEach(rc -> {
            try {
                ReferenceConfig<?> referenceConfig = (ReferenceConfig<?>) rc;
                referenceCache.get(rc, false);
            }
    }

可以看到引用服务中处理的就是ReferenceConfig配置

public <T> T get(ReferenceConfigBase<T> rc, boolean check) {
        String key = generator.generateKey(rc);
        Class<?> type = rc.getInterfaceClass();

        boolean singleton = rc.getSingleton() == null || rc.getSingleton();
        T proxy = null;
        // Check existing proxy of the same 'key' and 'type' first.
        if (singleton) {
            proxy = get(key, (Class<T>) type);
        } ...

        if (proxy == null) {
            List<ReferenceConfigBase<?>> referencesOfType = ConcurrentHashMapUtils.computeIfAbsent(referenceTypeMap, type, _t -> Collections.synchronizedList(new ArrayList<>()));
            referencesOfType.add(rc);
            List<ReferenceConfigBase<?>> referenceConfigList = ConcurrentHashMapUtils.computeIfAbsent(referenceKeyMap, key, _k -> Collections.synchronizedList(new ArrayList<>()));
            referenceConfigList.add(rc);
            proxy = rc.get(check);
        }

        return proxy;
    }

这里的get方法和示例代码中从缓存获取代理类是一致的,都是先从缓存中获取代理对象,不存在就初始化缓存,然后执行代理对象的创建流程

protected synchronized void init(boolean check) {
            ...

            ref = createProxy(referenceParameters);
        ...
    }

private T createProxy(Map<String, String> referenceParameters) {
        ...
            aggregateUrlFromRegistry(referenceParameters);

        invoker = protocolSPI.refer(interfaceClass, curUrl);

        ...

        URL consumerUrl = new ServiceConfigURL(CONSUMER_PROTOCOL, referenceParameters.get(REGISTER_IP_KEY), 0,
                referenceParameters.get(INTERFACE_KEY), referenceParameters);
        ...
        MetadataUtils.publishServiceDefinition(consumerUrl, consumerModel.getServiceModel(), getApplicationModel());

        // create service proxy
        return (T) proxyFactory.getProxy(invoker, ProtocolUtils.isGeneric(generic));
    }

创建Invoker

创建Invoker流程里也是需要先构建URL,这里也是先从注册中心构建URL

registry://1.2.3.4:32181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-consumer&dubbo=2.0.2&executor-management-mode=isolation&file-cache=true&pid=19540&registry=zookeeper&release=3.2.4&timestamp=1701174658297

然后通过Protocol类创建Invoker,按照Dubbo系列--服务导出及服务注册《四》中的描述

registry协议对应的实现类是InterfaceCompatibleRegistryProtocol,但是由于Wrapper类的存在,还是会形成如下的包装关系

image.png

我们还是依次看下每个Wrapper类的refer方法

  • InvokerCountWrapper:由于是registry协议,满足条件判断,因此没有加任何东西
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        if (UrlUtils.isRegistry(url)) {
            return protocol.refer(type, url);
        }
        ...
    }
  • ProtocolSerializationWrapper:没有加任何东西
@Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        return protocol.refer(type, url);
    }
  • ProtocolFilterWrapper:由于是registry协议,满足条件判断,因此没有加任何东西
@Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        if (UrlUtils.isRegistry(url)) {
            return protocol.refer(type, url);
        }
        ...
    }
  • QosProtocolWrapper:先启动一个Qos服务器,通过Netty框架监听在0.0.0.0:22222,和导出时一样

  • ProtocolListenerWrapper:由于是registry协议,满足条件判断,因此没有加任何东西

@Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        if (UrlUtils.isRegistry(url)) {
            return protocol.refer(type, url);
        }
      ...
    }
  • ProtocolSecurityWrapper:对代理的接口类型、接口方法中设计的参数类型、返回值类型就行放通

  • InterfaceCompatibleRegistryProtocol:最终的实现类,但是由于它继承自RegistryProtocol,且没有重写refer方法,因此会直接使用父类的、

public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        url = getRegistryUrl(url);
        Registry registry = getRegistry(url);
        ...

        Cluster cluster = Cluster.getCluster(url.getScopeModel(), qs.get(CLUSTER_KEY));
        URL consumerUrl = new ServiceConfigURL(
            p,
            null,
            null,
            parameters.get(REGISTER_IP_KEY),
            0, getPath(parameters, type),
            parameters,
            consumerAttribute
        );
        url = url.putAttribute(CONSUMER_URL_KEY, consumerUrl);
        ClusterInvoker<T> migrationInvoker = new MigrationInvoker<T>(registryProtocol, cluster, registry, type, url, consumerUrl);
        
       List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url);
        if (CollectionUtils.isEmpty(listeners)) {
            return invoker;
        }

        for (RegistryProtocolListener listener : listeners) {
            listener.onRefer(this, invoker, consumerUrl, url);
        }
        return migrationInvoker;
    }

这里会先构建注册URL,其实就是替换协议,真正的协议保存在参数registry=zookeeper

zookeeper://1.2.3.4:32181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-consumer&dubbo=2.0.2&executor-management-mode=isolation&file-cache=true&pid=19540&release=3.2.4&timestamp=1701174658297

然后创建协议对应的Registry,创建流程和服务导出过程是一样的,最终创建的是ZookeeperRegistry对象,进而创建Zookeeper客户端,并缓存

然后通过SPI方式加载Cluster的实现类,可以看到默认加载的是FailoverCluster

@SPI("failover")
public interface Cluster {
}

同样由于包装类的存在,最终会形成如下的包装关系


image.png

然后构建消费者URL

consumer://172.168.111.11/services.HelloService?application=dubbo-demo-api-consumer&background=false&dubbo=2.0.2&executor-management-mode=isolation&file-cache=true&interface=services.HelloService&methods=sayHello&pid=19540&register.ip=172.168.111.11&release=3.2.4&side=consumer&sticky=false&timestamp=1701174658287&unloadClusterRelated=false

然后创建了一个MigrationInvoker,并通过SPI方式加载监听器,默认情况下只有一个MigrationRuleListener监听器

最终会通过这个监听器来开始实际的创建Invoker流程,这里的MigrationInvoker可以认为是dubbo2dubbo3的兼容性改造

@Override
    public void migrateToApplicationFirstInvoker(MigrationRule newRule) {
        CountDownLatch latch = new CountDownLatch(0);
        refreshInterfaceInvoker(latch);
        refreshServiceDiscoveryInvoker(latch);

        // directly calculate preferred invoker, will not wait until address notify
        // calculation will re-occurred when address notify later
        calcPreferredInvoker(newRule);
    }
创建接口的Invoker

接口级别的Invoker对应着InterfaceCompatibleRegistryProtocol中的getInvoker方法

@Override
    public <T> ClusterInvoker<T> getInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {
        DynamicDirectory<T> directory = new RegistryDirectory<>(type, url);
        ...
        URL urlToRegistry = new ServiceConfigURL(
            parameters.get(PROTOCOL_KEY) == null ? CONSUMER : parameters.get(PROTOCOL_KEY),
            parameters.remove(REGISTER_IP_KEY),
            0,
            getPath(parameters, type),
            parameters
        );
        ...
        if (directory.isShouldRegister()) {
            directory.setRegisteredConsumerUrl(urlToRegistry);
            registry.register(directory.getRegisteredConsumerUrl());
        }
        directory.buildRouterChain(urlToRegistry);
        directory.subscribe(toSubscribeUrl(urlToRegistry));

        return (ClusterInvoker<T>) cluster.join(directory, true);
    }
  • 这里先创建了一个RegistryDirectory对象

  • 然后进行消费者URL构建

consumer://172.168.111.11/services.HelloService?application=dubbo-demo-api-consumer&background=false&dubbo=2.0.2&executor-management-mode=isolation&file-cache=true&interface=services.HelloService&methods=sayHello&pid=19540&release=3.2.4&side=consumer&sticky=false&timestamp=1701174658287&unloadClusterRelated=false

  • 并进行消费者注册,注册完成后,注册中心里可以看到消费者信息
[zk: localhost:2181(CONNECTED) 253] ls -R /
/
/dubbo
/dubbo/services.HelloService/consumers/consumer%3A%2F%2F172.168.111.11%2Fservices.HelloService%3Fapplication%3Ddubbo-demo-api-consumer%26background%3Dfalse%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.2%26executor-management-mode%3Disolation%26file-cache%3Dtrue%26interface%3Dservices.HelloService%26methods%3DsayHello%26pid%3D19540%26release%3D3.2.4%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1701174658287%26unloadClusterRelated%3Dfalse
  • 然后构造路由链,会有一个主链、一个被用链,当前链指向的是主链


    image.png

路由规则也是通过SPI方式加载,主要在RouterFactoryStateRouterFactory这两个接口的实现类

  • 最后是进行订阅,需要注意的是,这里会指定category=providers,configurators,routers,即这三种类型的配置都进行订阅

在服务导出的时候只订阅了configurators这一类别

再上面我们已经指出了,Registry的最终实现类是ZookeeperRegistry,因此最终会进入到它的订阅方法

@Override
    public void doSubscribe(final URL url, final NotifyListener listener) {
        try {
            ...
            } else {
               
                try {
                    List<URL> urls = new ArrayList<>();

                    for (String path : toCategoriesPath(url)) {
                        ...
                        // create "directories".
                        zkClient.create(path, false, true);

                        ...

                    notify(url, listener, urls);
                }...
    }

由于指定了category=providers,configurators,routers,因此这里的toCategoriesPath(url)会得到三个路径

  • /dubbo/services.HelloService/providers:服务的提供者信息,由于在服务导出的时候,已经将服务提供者记录在了这个节点下
[zk: localhost:2181(CONNECTED) 255] ls -R /
/dubbo/services.HelloService/providers/dubbo%3A%2F%2F172.168.111.11%3A20880%2Fservices.HelloService%3Fapplication%3Ddubbo-demo-api-provider%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dservices.HelloService%26methods%3DsayHello%26prefer.serialization%3Dfastjson2%2Chessian2%26release%3D3.2.4%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1701058538278

因此这里就可以将服务提供者信息加载到服务消费者中来

  • /dubbo/services.HelloService/configurators:服务的配置信息

  • /dubbo/services.HelloService/routers:服务的路由信息

我们这里重点关注下服务的提供者信息,因为下面会对服务提供者信息进行通知

由于RegistryDirectory实现了通知接口,因此最终会进入它的通知接口

@Override
    public synchronized void notify(List<URL> urls) {
        ...
        refreshOverrideAndInvoker(providerURLs);
    }

在它的通知接口里会创建Invoker

private void refreshInvoker(List<URL> invokerUrls) {
     invoker = protocol.refer(serviceType, url);       
}

首先是这里URL对应的是提供者的:

dubbo://172.168.111.11:20880/services.HelloService?application=dubbo-demo-api-provider&background=false&category=providers,configurators,routers&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=isolation&file-cache=true&generic=false&interface=services.HelloService&methods=sayHello&pid=19540&prefer.serialization=fastjson2,hessian2&release=3.2.4&service-name-mapping=true&side=provider&sticky=false&unloadClusterRelated=false

由于这里对应的协议是dubbo,因此最终的实现者啊DubboProtocol,我们看下它的refer方法

@Override
    public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
        ...
        DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
        invokers.add(invoker);

        return invoker;
    }

可以看到这里创建的是DubboInvoker,最主要的方法是获取客户端

private ExchangeClient initClient(URL url) {
         Exchangers.connect(url, requestHandler);
    }

@Override
    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);
    }

public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException {
       
        return url.getOrDefaultFrameworkModel().getExtensionLoader(Transporter.class).getAdaptiveExtension().connect(url, handler);
    }

可以看到客户端是通过SPI方式加载Transporter的实现类

@SPI(value = "netty", scope = ExtensionScope.FRAMEWORK)
public interface Transporter {
}

默认的实现类是Netty

@Override
    public Client connect(URL url, ChannelHandler handler) throws RemotingException {
        return new NettyClient(url, handler);
    }

因此最终创建的是Netty客户端,使用Netty客户端去连接服务提供者的Netty服务器

然后这个Netty客户端会保存在DubboInvoker中,然后返回的就是DubboInvoker

由于Protocol存在Wrapper类,最终会形成如下的包装类

image.png

包装的Invoker会缓存在RegistryDirectory对象中

image.png

能够正常连接的Invoker会放到validInvoker

至此完成了服务提供者的订阅

  • 最后是将RegistryDirectory通过Cluster包装返回

至此完成了接口的Invoker创建过程,并缓存在MigrationInvoker

创建应用的Invoker

创建应用的Invoker过程和接口的基本一致,但是存在些许差异

应用级别的Invoker对应着InterfaceCompatibleRegistryProtocol中的getServiceDiscoveryInvoker方法

@Override
    public <T> ClusterInvoker<T> getServiceDiscoveryInvoker(Cluster cluster, Registry registry, Class<T> type, URL url) {
        registry = getRegistry(super.getRegistryUrl(url));
        DynamicDirectory<T> directory = new ServiceDiscoveryRegistryDirectory<>(type, url);
        return doCreateInvoker(directory, cluster, registry, type);
    }
  • 首先进行URL协议重写,协议替换为service-discovery-registry,这点和服务导出里是一致的

service-discovery-registry://1.2.3.4:32181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-consumer&dubbo=2.0.2&executor-management-mode=isolation&file-cache=true&pid=19540&registry=zookeeper&release=3.2.4&timestamp=1701174658297

  • 由于此时协议变成了service-discovery-registry,因此Registry的实现类会变成ServiceDiscoveryRegistry,这个类在Dubbo系列--服务导出及服务注册《四》中已经详细说过了,它会创建一个ServiceDiscovery,对应的就是ZookeeperServiceDiscovery,订阅的是/services目录

  • 然后创建的是ServiceDiscoveryRegistryDirectory,它和接口级别的Invoker创建的RegistryDirectory不一样,但是继承于DynamicDirectory

  • 最后的创建Invoker方法doCreateInvoker和接口级别的是一样的,只是因为这里使用的是ServiceDiscoveryRegistry,订阅过程会稍有不同,其它的是一样的

我们详细看下它的订阅过程

@Override
    public void doSubscribe(URL url, NotifyListener listener) {
        ...

        Set<String> mappingByUrl = ServiceNameMapping.getMappingByUrl(url);

        String key = ServiceNameMapping.buildMappingKey(url);


        if (mappingByUrl == null) {
           
                mappingByUrl = serviceNameMapping.getMapping(url);
                try {
                    MappingListener mappingListener = new DefaultMappingListener(url, mappingByUrl, listener);
                    mappingByUrl = serviceNameMapping.getAndListen(this.getUrl(), url, mappingListener);
                    mappingListeners.put(url.getProtocolServiceKey(), mappingListener);
                } ...
        
        serviceNames = toTreeSet(serviceNames);
        String serviceNamesKey = toStringKeys(serviceNames);
        String serviceKey = url.getServiceKey();
        logger.info(String.format("Trying to subscribe from apps %s for service key %s, ", serviceNamesKey, serviceKey));

        // register ServiceInstancesChangedListener
       ...
                serviceInstancesChangedListener = serviceDiscovery.createListener(serviceNames);
                for (String serviceName : serviceNames) {
                    List<ServiceInstance> serviceInstances = serviceDiscovery.getInstances(serviceName);
                    if (CollectionUtils.isNotEmpty(serviceInstances)) {
                        serviceInstancesChangedListener.onEvent(new ServiceInstancesChangedEvent(serviceName, serviceInstances));
                    }
                }
               ...
    }
  • 这里会先从缓存中获取key=services.HelloService的名字服务映射关系

  • 缓存中不存在,则会从注册中心获取,在服务导出的时候已经注册了名字服务映射关系,因此这里可以获取到提供者应用名称dubbo-demo-api-provider

[zk: localhost:2181(CONNECTED) 223] ls -R /
/dubbo/mapping/services.HelloService

[zk: localhost:2181(CONNECTED) 225] get /dubbo/mapping/services.HelloService
dubbo-demo-api-provider
  • 然后再从注册中心获取这个应用名称对应的服务,在服务导出的时候已经注册过这个服务
[zk: localhost:2181(CONNECTED) 255] ls -R /
/services/dubbo-demo-api-provider/172.168.111.11:20880

[zk: localhost:2181(CONNECTED) 256] get /services/dubbo-demo-api-provider/172.168.111.11:20880
{"name":"dubbo-demo-api-provider","id":"172.168.111.11:20880","address":"172.168.111.11","port":20880,"sslPort":null,"payload":{"@class":"org.apache.dubbo.registry.zookeeper.ZookeeperInstance","id":"172.168.111.11:20880","name":"dubbo-demo-api-provider","metadata":{"dubbo.endpoints":"[{\"port\":20880,\"protocol\":\"dubbo\"}]","dubbo.metadata-service.url-params":"{\"prefer.serialization\":\"fastjson2,hessian2\",\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"3.2.4\",\"side\":\"provider\",\"port\":\"20880\",\"protocol\":\"dubbo\"}","dubbo.metadata.revision":"810c0d1c672d1f93d39e7b23f39abf27","dubbo.metadata.storage-type":"local","timestamp":"1701058538278"}},"registrationTimeUTC":1701058540261,"serviceType":"DYNAMIC","uriSpec":null}

这里消费者会先订阅/services/dubbo-demo-api-provider这个服务,用于监听这个应用下的所有实例

然后再把这个路径下的所有实例读出来,构建URL

最后通过notify通知机制,回调ServiceDiscoveryRegistryDirectory中的notify方法

@Override
    public synchronized void notify(List<URL> instanceUrls) {
       ...

        refreshOverrideAndInvoker(instanceUrls);
    }

它的notify方法就和接口级别的一样了,也是创建Invoker,由于这里获取到的提供者信息中的协议也是dubbo,所以最终的Invoker也是有DubboProtocol来创建,和接口级别的是完全一致

至此完成了应用级别的Invoker创建,并且会优先使用应用级别的Invoker

private synchronized void calcPreferredInvoker(MigrationRule migrationRule) {
        
        Set<MigrationAddressComparator> detectors = ScopeModelUtil.getApplicationModel(consumerUrl == null ? null : consumerUrl.getScopeModel())
            .getExtensionLoader(MigrationAddressComparator.class).getSupportedExtensionInstances();
        if (CollectionUtils.isNotEmpty(detectors)) {
            // 这里由于接口级别和应用级别都存在Invoker,而且没有指定阈值,默认就是true,会优先使用应用级别的Invoker
            if (detectors.stream().allMatch(comparator -> comparator.shouldMigrate(serviceDiscoveryInvoker, invoker, migrationRule))) {
                this.currentAvailableInvoker = serviceDiscoveryInvoker;
            } else {
                this.currentAvailableInvoker = invoker;
            }
        }
    }

创建对象

在回过头来看下创建对象的流程

private T createProxy(Map<String, String> referenceParameters) {
       
        createInvoker();

        // create service proxy
        return (T) proxyFactory.getProxy(invoker, ProtocolUtils.isGeneric(generic));
    }

可以看到创建完成Invoker后,就通过ProxyFactory来创建代理对象,在服务导出文中已经详解过这个接口了,ProxyFactory的接口定义中指定了默认的实现类是javassist对应的JavassistProxyFactory

public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        try {
            return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
        } catch (Throwable fromJavassist) {
            // 异常后使用JDK方式重试
        }
    }

这里主要依赖Proxy这个工具类来创建接口的代理实现类,这个工具类会把动态生成的类缓存起来,它动态生成的实现类如下

package services;

public class HelloServiceDubboProxy0 implements services.HelloService, org.apache.dubbo.rpc.service.EchoService, org.apache.dubbo.rpc.service.Destroyable, org.apache.dubbo.common.bytecode.ClassGenerator.DC {

            public static java.lang.reflect.Method[] methods;

            private java.lang.reflect.InvocationHandler handler;

            public HelloServiceDubboProxy0(java.lang.reflect.InvocationHandler handler) {
                       handler=$1;
            }

            public HelloServiceDubboProxy0() {
            }
        
            public java.lang.String sayHello(java.lang.String arg0) {
                     Object[] args = new Object[1];
                    // $w是javassist中的类型转换,基础类型转为包装类型,其它类型会忽略这个
                     args[0] = ($w)$1; 
                     Object ret = handler.invoke(this, methods[0], args); 
                     return (java.lang.String)ret;
            }

            
            public java.lang.Object $echo(java.lang.Object arg0) { 
                      Object[] args = new Object[1];
                      args[0] = ($w)$1; 
                     Object ret = handler.invoke(this, methods[1], args); 
                     return (java.lang.Object) ret;
           }

           public void $destroy() { 
                     Object[] args = new Object[0]; 
                     Object ret = handler.invoke(this, methods[2], args);
          }
}

可以看到动态生成的代理类不仅会实现目标接口,还会实现三个工具接口,并且会生成一个接收InvocationHandler的构造函数

所以生成代理对象的时候Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker))使用的是这个构造函数,直接创建了一个InvokerInvocationHandler对象作为入参,并且包装了我们之前创建的Invoker对象

至此,就完成了代理对象的创建


image.png

相关文章

  • dubbo-Reference注解改进

    1.dubbo服务过多引用的问题 1.1 dubbo服务以xml配置消费者 由于引用多个dubbo服务时,在未使用...

  • Dubbo服务引用

    1 Dubbo服务引用流程 2 Dubbo引用源码分析 2.1 创建代理 Dubbo会为引用服务创建一个代理对象,...

  • dubbo源码分析-服务调用

    dubbo服务调用,就是服务消费者发起调用服务提供者接口的过程。是对前面服务导出,服务引用,服务集群、路由和负载均...

  • dubbo源码解析-逻辑层设计之服务降级

    前言 在dubbo服务暴露系列完结之后,按计划来说是应该要开启dubbo服务引用的讲解.但是现在到了年尾,一些朋友...

  • Dubbo引用服务

    引用服务时序 引用服务 1. 直连引用服务:[https://dubbo.apache.org/zh/docs/v...

  • dubbo技术内幕三 ReferenceBean refer过程

    在dubbo里面比较复杂的是dubbo服务的refer过程。对dubbo service服务的引用都封装在Refe...

  • dubbo服务引用

    dubbo是一款开源的高性能Java RPC框架,可以像调用本地函数一样,调用远程服务。下面对dubbo服务引用部...

  • 【Dubbo】服务引用

    在springApplication.xml中配置服务引用申明服务接口,我们就可以方便的注入远端的服务代理,通过该...

  • Dubbo 服务引用

    1. 前言 在服务导出过程中,provider将自己的服务暴露了出来,并注册到注册中心中。对于服务引用无非就是从注...

  • Dubbo服务引用

    服务引用 服务引用的流程可以概括为以下五点 两种模式(饿汉式/懒汉式) 组装URL并向注册中心注册 获取服务提供者...

网友评论

      本文标题:Dubbo系列--消费者服务引用《五》

      本文链接:https://www.haomeiwen.com/subject/qygbwdtx.html