Dubbo精要

1、为什么需要 Dubbo?

  • 分布式系统中的服务调用和协调问题:在分布式系统中,服务之间的相互依赖会导致复杂的通信和协调问题。Dubbo提供了高效的服务调用和自动注册、发现等功能,使得构建分布式应用程序更加容易。
  • 服务治理和服务调用链追踪:Dubbo可以帮助我们实现服务治理、服务调用链追踪、服务降级、服务熔断等功能,这对于复杂的服务环境非常重要。
  • 服务拆分和扩展性:随着用户量的增多,应用服务器可能会面临负载压力。此时,我们可以使用Dubbo进行服务拆分,通过增加应用服务器来提高系统的扩展性。
  • 动态服务发现和负载均衡:Dubbo提供了动态的服务注册和发现机制,以及负载均衡功能,这可以帮助我们在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖。
  • 服务间依赖关系的可视化:当服务的调用量越来越大,服务的容量问题就暴露出来。Dubbo可以帮助我们自动画出应用间的依赖关系图,以帮助架构师理清理关系。

2、Dubbo 的主要应用场景?

      通常有四点,如下: RPC 分布式服务,拆分应用进行服务化,提高开发效率,调优性能,节省竞争资源配置管理,解 决服务的地址信息剧增,配置困难的问题 服务依赖,解决服务间依赖关系错踪复杂的问题 服务扩容,解决随着访问量的不断增大,动态扩展服务提供方的机器的问题。

3、Dubbo 的核心功能?

Dubbo主要就是如下 3 个核心功能:

(1)Remoting:网络通信框架,提供对多种 NIO 框架抽象封装,包括“同步转异步”和“请求-响应”模式 的信息交换方式。

(2)Cluster:服务框架,提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均 衡,失败容错,地址路由,动态配置等集群支持。

(3)Registry:服务注册,基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透 明,使服务提供方可以平滑增加或减少机器。

4、Dubbo 服务注册与发现的流程?

     流程说明: Provider(提供者)绑定指定端口并启动服务 指供者连接注册中心,并发本机IP、端口、应用信息和提供服务信息发送至注册中心存储 Consumer(消费者),连接注册中心 ,并发送应用信息、所求服务信息至注册中心 注册中心根据 消费 者所求服务信息匹配对应的提供者列表发送至Consumer 应用缓存。 Consumer 在发起远程调用时基于缓存的消费者列表择其一发起调用。 Provider 状态变更会实时通知注册中心、在由注册中心实时推送至Consumer。

    设计的原因: Consumer 与Provider 解偶,双方都可以横向增减节点数。 注册中心对本身可做对等集群,可动态增减节点,并且任意一台宕掉后,将自动切换到另一台去中 心化,双方不直接依懒注册中心,即使注册中心全部宕机短时间内也不会影响服务的调用服务提供 者无状态,任意一台宕掉后,不影响使用。

5、Dubbo 的服务调用流程?

1) 从client到server经历了编码,序列化,反序列化,解码 的正常网络调用流程, 在nettyServer中处理。 

2) client采用代理的机制 。

3) server处理请求的方式通常为分发请求到线程池,同步阻塞或异步非阻塞返回结果。

6、Dubbo 支持哪些协议,每种协议的应用场景、优缺点?

 dubbo默认:

7、Dubbo 有些哪些注册中心?

推荐使用 Zookeeper 、Nacos作为注册中心,还有 Redis、Multicast、Simple 注册中心,但不推荐。

8、Dubbo 的注册中心集群挂掉,如何正常消费?

可以的,消费者在启动时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。 每次调用时,按照本地存储的地址进行调用。 消费者本地有一个生产者的列表,他会按照列表继续工作,倒是无法从注册中心去同步最新的服务列 表,短期的注册中心挂掉是不要紧的,但一定要尽快修复。 挂掉是不要紧的,但前提是你没有增加新的服务(节点没有变动),如果你要调用新的服务,则是不能 办到的。

9、Dubbo 集群提供了哪些负载均衡策略?

  • Random LoadBalance: 随机选取提供者策略,有利于动态调整提供者权重。截面碰撞率高,调用次数越多,分布越均匀。
  • RoundRobin LoadBalance: 轮循选取提供者策略,平均分布,但是存在请求累积的问题。
  • LeastActive LoadBalance: 最少活跃调用策略,解决慢提供者接收更少的请求。
  • ConstantHash LoadBalance: 一致性 Hash 策略,使相同参数请求总是发到同一提供者,一台机器宕机,可以基于虚拟节点,分摊至其他提供者,避免引起提供者的剧烈变动。

默认为 Random 随机调用。

10、Dubbo 的集群容错方案有哪些?

  • Failover Cluster失败自动切换: dubbo的默认容错方案,当调用失败时自动切换到其他可用的节点,具体的重试次数和间隔时间可用通 过引用服务的时候配置,默认重试次数为1是只调用一次。

  • Failback Cluster失败自动恢复: 在调用失败,记录日志和调用信息,然后返回空结果给consumer,并且通过定时任务每隔5秒对失败的 调用进行重试

  • Failfast Cluster快速失败: 只会调用一次,失败后立刻抛出异常

  • Failsafe Cluster失败安全: 调用出现异常,记录日志不抛出,返回空结果 Forking Cluster并行调用多个服务提供者: 通过线程池创建多个线程,并发调用多个provider,结果保存到阻塞队列,只要有一个provider成功返 回了结果,就会立刻返回结果

  • Broadcast Cluster广播模式: 逐个调用每个provider,如果其中一台报错,在循环调用结束后,抛出异常。 

第一个,failover

这也是Dubbo中默认的一个集群容错技术,failover翻译成中文叫故障转移,见名思义,它是指发现服务提供者不可用时会尝试调用集群中其他的服务提供者,dubbo中默认重试2次。源码如下:

public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
   
        List<Invoker<T>> copyInvokers = invokers;
        checkInvokers(copyInvokers, invocation);
        String methodName = RpcUtils.getMethodName(invocation);
        //获取重试次数,默认2次 加当前调用,总共3次
        int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
        if (len <= 0) {
   
            len = 1;
        }
        // retry loop.
        RpcException le = null; // last exception.
        List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
        Set<String> providers = new HashSet<String>(len);
        //循环重试调用
        for (int i = 0; i < len; i++) {
   
            //Reselect before retry to avoid a change of candidate `invokers`.
            //NOTE: if `invokers` changed, then `invoked` also lose accuracy.
            if (i > 0) {
   
                checkWhetherDestroyed();
                copyInvokers = list(invocation);
                // check again
                checkInvokers(copyInvokers, invocation);
            }
            Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
            invoked.add(invoker);
            RpcContext.getContext().setInvokers((List) invoked);
            try {
   
                Result result = invoker.invoke(invocation);
                if (le != null && logger.isWarnEnabled()) {
   
                    logger.warn("Although retry the method " + methodName
                            + " in the service " + getInterface().getName()
                            + " was successful by the provider " + invoker.getUrl().getAddress()
                            + ", but there have been failed providers " + providers
                            + " (" + providers.size() + "/" + copyInvokers.size()
                            + ") from the registry " + directory.getUrl().getAddress()
                            + " on the consumer " + NetUtils.getLocalHost()
                            + " using the dubbo version " + Version.getVersion() + ". Last error is: "
                            + le.getMessage(), le);
                }
                return result;
            } catch (RpcException e) {
   
                if (e.isBiz()) {
    // biz exception.
                    throw e;
                }
                le = e;
            } catch (Throwable e) {
   
                le = new RpcException(e.getMessage(), e);
            } finally {
   
                providers.add(invoker.getUrl().getAddress());
            }
        }
        throw new RpcException(le.getCode(), "Failed to invoke the method "
                + methodName + " in the service " + getInterface().getName()
                + ". Tried " + len + " times of the providers " + providers
                + " (" + providers.size() + "/" + copyInvokers.size()
                + ") from the registry " + directory.getUrl().getAddress()
                + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
                + Version.getVersion() + ". Last error is: "
                + le.getMessage(), le.getCause() != null ? le.getCause() : le);
    }

 第二个,fastfail

这种是快速失败机制,就是调用失败时立即报错,通常用于非幂等的操作。

@Override
    public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
   
        checkInvokers(invokers, invocation);
        Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
        try {
   
            return invoker.invoke(invocation);
        } catch (Throwable e) {
   
            if (e instanceof RpcException && ((RpcException) e).isBiz()) {
    // biz exception.
                throw (RpcException) e;
            }
            //失败了,直接抛异常
            throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0,
                    "Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getSimpleName()
                            + " select from all providers " + invokers + " for service " + getInterface().getName()
                            + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost()
                            + " use dubbo version " + Version.getVersion()
                            + ", but no luck to perform the invocation. Last error is: " + e.getMessage(),
                    e.getCause() != null ? e.getCause() : e);
        }
    }

第三个,failsafe

这种是失败安全机制,失败之后不抛异常也不重试,而是忽略异常,单纯记录一下日志,返回空结果。源码如下:

@Override
    public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
   
        try {
   
            checkInvokers(invokers, invocation);
            Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
            return invoker.invoke(invocation);
        } catch (Throwable e) {
   
            //忽略异常,记录日志,返回空结果
            logger.error("Failsafe ignore exception: " + e.getMessage(), e);
            return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore
        }
    }
 第四个,broadcast

这种是广播调用,任何一个服务提供者报错就报错。这种集群容错方式的使用场景是用来更新本地缓存,如果某个数据在某台服务器更新了,可用同步到集群中的其他服务器。

public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
   
        checkInvokers(invokers, invocation);
        RpcContext.getContext().setInvokers((List) invokers);
        RpcException exception = null;
        Result result = null;
        //调用所有服务提供者
        for (Invoker<T> invoker : invokers) {
   
            try {
   
                result = invoker.invoke(invocation);
            } catch (RpcException e) {
   
                exception = e;
                logger.warn(e.getMessage(), e);
            } catch (Throwable e) {
   
                exception = new RpcException(e.getMessage(), e);
                logger.warn(e.getMessage(), e);
            }
        }
        //只要有一台异常,就报错
        if (exception != null) {
   
            throw exception;
        }
        return result;
    }
第五个,failback

这种是失败降级,失败后会记录请求并且定时重试,忽略异常后返回空

源码如下:

@Override
    protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
   
        Invoker<T> invoker = null;
        try {
   
            checkInvokers(invokers, invocation);
            invoker = select(loadbalance, invocation, invokers, null);
            return invoker.invoke(invocation);
        } catch (Throwable e) {
   
            logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: "
                    + e.getMessage() + ", ", e);
            //新增失败的任务 到时间轮队列
            addFailed(loadbalance, invocation, invokers, invoker);
            return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore
        }
    }

 第六个,forking

这种是并行调用,只要有1个成功就成功,全部失败才算失败,可通过forks="2" 来设置最大并行数。

源码如下:

//循环每个服务提供者,多线程并行调用
for (final Invoker<T> invoker : selected) {
   
                executor.execute(new Runnable() {
   
                    @Override
                    public void run() {
   
                        try {
   
                            Result result = invoker.invoke(invocation);
                            ref.offer(result);
                        } catch (Throwable e) {
   
                            int value = count.incrementAndGet();
                            //失败次数大于等于了提供者数量,说明全部失败
                            if (value >= selected.size()) {
   
                                ref.offer(e);
                            }
                        }
                    }
                });
            }
try {
   
                Object ret = ref.poll(timeout, TimeUnit.MILLISECONDS);
                //如果有失败记录,说明全部都失败了则失败
                if (ret instanceof Throwable) {
   
                    Throwable e = (Throwable) ret;
                    throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e);
                }
                //否则返回成功
                return (Result) ret;
            } catch (InterruptedException e) {
   
                throw new RpcException("Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e);
            }

11、Dubbo 支持哪些序列化方式?

  • Dubbo:单一长连接和 NIO 异步通讯,适合大并发小数据量的服务调用,以及消费者远大于提供者。传输协议 TCP,异步 Hessian 序列化。Dubbo推荐使用dubbo协议。
  • RMI:采用 JDK 标准的 RMI 协议实现,传输参数和返回参数对象需要实现 Serializable 接口,使用 Java 标准序列化机制,使用阻塞式短连接,传输数据包大小混合,消费者和提供者个数差不多,可传文件,传输协议 TCP。多个短连接 TCP 协议传输,同步传输,适用常规的远程服务调用和 RMI 互操作。在依赖低版本的 Common-Collections 包,Java 序列化存在安全漏洞。
  • WebService:基于 WebService 的远程调用协议,集成 CXF 实现,提供和原生 WebService 的互操作。多个短连接,基于 HTTP 传输,同步传输,适用系统集成和跨语言调用。
  • HTTP:基于 Http 表单提交的远程调用协议,使用 Spring 的 HttpInvoke 实现。多个短连接,传输协议 HTTP,传入参数大小混合,提供者个数多于消费者,需要给应用程序和浏览器 JS 调用。
  • Hessian:集成 Hessian 服务,基于 HTTP 通讯,采用 Servlet 暴露服务,Dubbo 内嵌 Jetty 作为服务器时默认实现,提供与 Hession 服务互操作。多个短连接,同步 HTTP 传输,Hessian 序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件。
  • Memcache:基于 Memcache实现的 RPC 协议。
  • Redis:基于 Redis 实现的RPC协议。

12、说说一次 Dubbo 服务请求流程?

13、说说 Dubbo 工作原理

工作原理分 10 层:

第一层:service 层,接口层,给服务提供者和消费者来实现的(留给开发人员来实现);

第二层:config 层,配置层,主要是对 Dubbo 进行各种配置的,Dubbo 相关配置;

第三层:proxy 层,服务代理层,透明生成客户端的 stub 和服务单的 skeleton,调用的是接口,实现 类没有,所以得生成代理,代理之间再进行网络通讯、负责均衡等;

第四层:registry 层,服务注册层,负责服务的注册与发现;

第五层:cluster 层,集群层,封装多个服务提供者的路由以及负载均衡,将多个实例组合成一个服 务;

第六层:monitor 层,监控层,对 rpc 接口的调用次数和调用时间进行监控;

第七层:protocol 层,远 程调用层,封装 rpc 调用;

第八层:exchange 层,信息交换层,封装请求响应模式,同步转异步;

第九层:transport 层,网络传输层,抽象 mina 和 netty 为统一接口;

第十层:serialize 层,数据序列化层。

14、注册中心挂了,consumer 还能不能调用 provider?

因为刚开始初始化的时候,consumer 会将需要的所有提供者的地址等信息拉取到本地缓存,所以注册 中心挂了可以继续通信。 但是 provider 挂了,那就没法调用了。

15、怎么实现动态感知服务下线的呢?

服务订阅通常有 pull 和 push 两种方式:

pull 模式需要客户端定时向注册中心拉取配置;

push 模式采用注册中心主动推送数据给客户端。

Dubbo ZooKeeper 注册中心采用是事件通知与客户端拉取方式。 服务第一次订阅的时候将会拉取对应目录下全量数据,然后在订阅的节点注册一个 watcher。 一旦目录节点下发生任何数据变化, ZooKeeper 将会通过 watcher 通知客户端。 客户端接到通知,将会重新拉取该目录下全量数据,并重新注册 watcher。

利用这个模式,Dubbo 服务就可以做到服务的动态发现。 注意:ZooKeeper 提供了“心跳检测”功能,它会定时向各个服务提供者发送一个请求(实际上建立的是 一个 socket 长连接),如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其剔除。

16、服务提供者没挂,但在注册中心里看不到?

首先,确认服务提供者是否连接了正确的注册中心,不只是检查配置中的注册中心地址,而且要检查实 际的网络连接。 其次,看服务提供者是否非常繁忙,比如压力测试,以至于没有CPU片段向注册中心发送心跳,这种情 况减小压力将自动恢复。

17、说说Dubbo的优先级配置

配置优先级别

1.以timeout为例,显示了配置的查找顺序,其他retries,loadbalance等类似。

(1) 方法级优先,接口级次之,全局配置在次之

(2) 如果级别一样,则消费方优先,提供方次之

(3) 其中,服务提供方配置,通过URL经由注册中心传递给消费方

2.建议由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消费方 同时引用多个服务,就不需要关心每个服务的超时设置。

18、聊聊Dubbo SPI机制?

SPI(Service Provider Interface),是一种服务发现机制,其实就是将结构的实现类写入配置当中,在服 务加载的时候将配置文件独处,加载实现类,这样就可以在运行的时候,动态的帮助接口替换实现类。 Dubbo的SPI其实是对java的SPI进行了一种增强,可以按需加载实现类之外,增加了 IOC 和 AOP 的特 性,还有自适应扩展机制。 SPI在dubbo应用很多,包括协议扩展、集群扩展、路由扩展、序列化扩展等等。 Dubbo对于文件目录的配置分为了三类。

1.META-INF/services/ 目录: 该目录下的 SPI 配置文件是为了用来兼容 Java SPI 。

2.META-INF/dubbo/ 目录: 该目录存放用户自定义的 SPI 配置文件。

3.META-INF/dubbo/internal/ 目录: 该目录存放 Dubbo 内部使用的 SPI 配置文件。

19、Dubbo的SPi和JAVA的SPI有什么区别?

Java Spi Java SPI 在查找扩展实现类的时候,遍历 SPI 的配置文件,并且将实现类全部实例化 Dubbo Spi

1,对 Dubbo 进行扩展,不需要改动 Dubbo 的源码

2,延迟加载,可以一次只加载自己想要加载的扩展实现。

3,增加了对扩展点 IOC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。

4,Dubbo 的扩展机制能很好的支持第三方 IoC 容器,默认支持 Spring Bean。

20、说下Dubbo的服务引用的流程。

1.Dubbo客户端根据config文件里的信息从注册中心里订阅服务,并缓存到本地,后续的服务相关信息 的会动态更新到本地。

2.DubboProtocol根据provider的地址和接口连接到服务端server,开启客户端client,再创建 invoker。

3.用invoker为服务接口生成代理对象,这个代理对象是用来远程调用。 相关流程如下图所示。

21、dubbo配置

1. XML配置

Dubbo的XML配置是最早的配置方式,在配置过程中需要编写XML文件,指定Dubbo相关的标签和属性。其中,最基本的配置是服务提供者和服务消费者的相关配置,如下:

<!-- 服务提供者注册到注册中心 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>

<!-- 暴露服务 -->
<dubbo:service interface="com.xxx.xxxService" ref="xxxServiceImpl" timeout="3000" />

<!-- 引用服务 -->
<dubbo:reference interface="com.xxx.xxxService" id="xxxService" timeout="3000" />

在这段XML配置中,我们首先在标签中指定了注册中心的地址信息,然后在标签中指定了服务提供者的接口和实现类,以及引用服务的接口和实现。timeout属性用于设置超时时间。

除了服务提供者和服务消费者的相关配置外,还有其他相关的配置。比如,可以使用dubbo:protocol标签指定Dubbo使用的协议类型和端口号,同时也可以在dubbo:method标签中为方法单独指定超时时间等参数。

  • 服务提供者:
  • DemoService.java:
package org.apache.dubbo.demo;

public interface DemoService {
    String sayHello(String name);
}
  • 在服务提供方实现接口
  • DemoServiceImpl.java:
package org.apache.dubbo.demo.provider;
import org.apache.dubbo.demo.DemoService;

public class DemoServiceImpl implements DemoService {
    public String sayHello(String name) {
        return "Hello " + name;
    }
}
  •  用 Spring 配置声明暴露服务
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:property-placeholder/>

    <dubbo:application name="demo-provider"/>

    <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>

    <dubbo:provider token="true"/>

    <bean id="demoService" class="org.apache.dubbo.samples.basic.impl.DemoServiceImpl"/>

    <dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService"/>

</beans>
  • 加载 Spring 配置
public class Application {

    public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-provider.xml");
        context.start();

        System.out.println("dubbo service started");
        // to hang up main thread
        new CountDownLatch(1).await();
    }
}
  • 服务消费者
  • 通过 Spring 配置引用远程服务 
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:property-placeholder/>

    <dubbo:application name="demo-consumer"/>

    <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>

    <dubbo:reference id="demoService" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService"/>

</beans>
  • 加载 Spring 配置,并调用远程服务 
public class Application {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-consumer.xml");
        context.start();
        GreetingsService greetingsService = (GreetingsService) context.getBean("greetingsService");

        String message = greetingsService.sayHi("dubbo");
        System.out.println("Receive result ======> " + message);
        System.in.read();
        System.exit(0);
    }

}
2. 注解配置

注解配置是一种比较简便的配置方式,可以直接在Java代码中使用注解指定Dubbo相关的配置信息。使用注解配置时,需要在配置类中添加@EnableDubbo注解开启Dubbo相关功能,示例如下:

@Configuration
@EnableDubbo(scanBasePackages = "com.xxx.service.impl")
public class DubboConfig {
}

其中,scanBasePackages属性指定了Dubbo扫描的包路径。然后就可以在服务提供者和服务消费者的实现类中使用Dubbo提供的注解进行配置,示例如下:

@Service(timeout = 3000)
public class XxxServiceImpl implements XxxService {
    
    @Override
    public String hello(String name) {
        return "Hello " + name;
    }
}

对于服务消费者,则可以使用@DubboReference注解引用服务,示例如下:

@Service
public class XxxConsumer {
@DubboReference(timeout = 3000)
private XxxService xxxService;

public String hello(String name) {
    return xxxService.hello(name);
}
}

在这个例子中,我们使用@DubboReference注解指定了服务的接口和超时时间,然后在XxxConsumer类中通过xxxService调用服务。

3. 属性配置

属性配置是一种比较灵活的配置方式,它允许我们在配置文件中定义属性,然后在代码中读取这些属性并进行相关操作。使用属性配置时,我们需要在代码中创建一个DubboProperties对象,并将其中的属性值通过@ConfigurationProperties注解注入到该对象中。示例如下:

@Component
@ConfigurationProperties(prefix = "dubbo")
public class DubboProperties {
private String registryAddress;

// get/set方法省略
}

然后,我们可以使用这个DubboProperties对象中定义的属性配置Dubbo相关的参数,示例如下:

@Service(timeout = "#{dubboProperties.timeout}")
public class XxxServiceImpl implements XxxService {

@Autowired
private DubboProperties dubboProperties;

@Override
public String hello(String name) {
    return "Hello " + name;
}
}

在这个例子中,我们使用了#{dubboProperties.timeout}的方式,读取DubboProperties对象中的timeout属性来指定服务超时时间。我们还可以在DubboProviders对象中定义其他属性,在需要的地方使用${}的方式读取这些属性。

常用注解

@DubboService 注解

定义好 Dubbo 服务接口后,提供服务接口的实现逻辑,并用 @DubboService 注解标记,就可以实现 Dubbo 的服务暴露

@DubboService
public class DemoServiceImpl implements DemoService {}

如果要设置服务参数,@DubboService 也提供了常用参数的设置方式。如果有更复杂的参数设置需求,则可以考虑使用其他设置方式

@DubboService(version = "1.0.0", group = "dev", timeout = 5000)
public class DemoServiceImpl implements DemoService {}

 @DubboReference 注解

@Component
public class DemoClient {
    @DubboReference
    private DemoService demoService;
}

@DubboReference 注解将自动注入为 Dubbo 服务代理实例,使用 demoService 即可发起远程服务调用

@EnableDubbo 注解

@EnableDubbo 注解必须配置,否则将无法加载 Dubbo 注解定义的服务,@EnableDubbo 可以定义在主类上

@SpringBootApplication
@EnableDubbo
public class ProviderApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(ProviderApplication.class, args);
    }
}

 Spring Boot 注解默认只会扫描 main 类所在的 package,如果服务定义在其它 package 中,需要增加配置 EnableDubbo(scanBasePackages = {"org.apache.dubbo.springboot.demo.provider"})

22、Dubbo容器

23、Dubbo日式组件设计

适配众多日志框架,包括自定义日志打印格式。

24、Dubbo的状态统计/监控

25、集成Nacos https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/metadata-center/nacos/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/873902.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 热题 100 回顾5

干货分享&#xff0c;感谢您的阅读&#xff01;原文见&#xff1a;LeetCode 热题 100 回顾_力code热题100-CSDN博客 一、哈希部分 1.两数之和 &#xff08;简单&#xff09; 题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标…

CentOS Stream 8中安装和使用 Docker

docker安装包-CSDN博客 〇、常用的docker命令 docker的作用&#xff1a; 快速进行软件的安装&#xff0c;便于软件环境的维护 docker的镜像: 压缩了指定软件的安装包的文件。使用镜像文件创建容器 docker的容器: 容器可以理解为就是一台小电脑。安装的linux系统&am…

C++入门基础篇

引言 说到编程语言常常听到的就是C语言C Java 。C语言是面向过程的&#xff0c;C是和Java是面向对象的&#xff0c;那么什么是面向对象呢&#xff1f;什么又是面向过程呢&#xff1f;C是什么&#xff1f;封装、继承、多态是什么&#xff1f;且听我絮絮叨叨。 C入门基础 1.命名…

SpringBoot OAuth2自定义登陆/授权页

背景 5 月份的时候&#xff0c;我实践并整理了一篇博客&#xff1a;SpringBoot搭建OAuth2&#xff0c;该博客完成之后&#xff0c;很长一段时间里我都有种意犹未尽的感觉。诚然&#xff0c;我把OAuth2搭起来了&#xff0c;各种场景的用例也跑通了&#xff0c;甚至源码也看了&am…

《花100块做个摸鱼小网站! 》第六篇—将小网站部署到云服务器上

⭐️基础链接导航⭐️ 服务器 → ☁️ 阿里云活动地址 看样例 → &#x1f41f; 摸鱼小网站地址 学代码 → &#x1f4bb; 源码库地址 一、前言 到这一篇我们终于把环境搭好&#xff0c;也做好了几个热搜小组件&#xff0c;为了让我们方便展示成果或者方便自己摸鱼&#xff0c…

2024最新!Facebook手机版和网页版改名教程!

Facebook作为全球最大的社交平台之一&#xff0c;允许用户自定义名字和昵称。在Facebook更新姓名可以帮助您更好的展现账号形象。本文将为您提供详细的步骤指导&#xff0c;帮助您在手机APP和网页版上轻松完成Facebook改名操作。 Facebook手机版改名 打开Facebook APP并登录账号…

DataGridView用法合集【精品】

目录 1.当前的单元格属性取得、变更 2.DataGridView编辑属性 3.DataGridView最下面一列新追加行非表示 4.判断当前选中行是否为新追加的行 5. DataGridView删除行可否设定 6. DataGridView行列不表示和删除 7. DataGridView行列宽度高度设置为不能编辑 8. DataGridView行…

SQL进阶技巧:如何利用SQL解决趣味赛马问题?| 非等值关联匹配问题

目录 0 问题描述 1 数据准备 2 问题分析 方法一:先分后合思想 方法2:非等值关联匹配 3 小结 0 问题描述 有一张赛马记录表,如下所示: create table RacingResults ( trace_id char(3) not null,race_date date not null, race_nbr int not null,win_name char(30) n…

【北京迅为】《STM32MP157开发板使用手册》-第十四章 QtE5.12应用开发

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

企业品牌声量统计怎么做?有没有什么工具?

企业在进行社交媒体推广宣传的过程中&#xff0c;通常需要关注品牌声量&#xff0c;借此衡量品牌传播效果、进行投放营销复盘等。也可以辅助下一步品牌策略的制定。那品牌声量是什么&#xff0c;怎么去统计这个品牌声量数据呢&#xff1f; 品牌声量是什么&#xff1f; 简单来…

mysql笔记3(数据库、表和数据的基础操作)

文章目录 一、数据库的基础操作1. 显示所有的仓库(数据库)2. 创建数据库注意(命名规范)&#xff1a; 3. 删除数据库4. 查看创建数据库的SQL5. 创建数据库时跟随字符编码6. 修改数据库的字符编码 二、表的基础操作1. 引入表的思维2. 引用数据库3. 查看该数据库下面的表4. 创建表…

全网最适合入门的面向对象编程教程:46 Python函数方法与接口-函数与事件驱动框架

全网最适合入门的面向对象编程教程&#xff1a;46 Python 函数方法与接口-函数与事件驱动框架 摘要&#xff1a; 函数是 Python 中的一等公民,是一种可重用的代码块,用于封装特定的逻辑&#xff1b;事件驱动框架是一种编程模式&#xff0c;它将程序的控制流转移给外部事件,如用…

vscode docker debug python

1. 安装Vscode插件 ”Docker“”Dev Containers““Remote - ssh” 2. 进入Docker环境 点击左侧 Docker图标&#xff0c;选择Containers 对容器进行右键启动 生成新页面直接进行选择文件路径即可&#xff0c;之后得操作均在容器内进行

6.1排序——插入排序与希尔排序

本篇博客来梳理两种常见排序算法&#xff1a;插入排序与希尔排序 常见的排序算法如图 写排序算法的原则&#xff1a;先写单趟&#xff0c;再写整体 一、直接插入排序 1&#xff0e;算法思想 先假定第一个数据有序&#xff0c;把第二个数据插入&#xff1b;再假设前两个数据…

读取、写入、生成txt文本文档详解——C#学习笔记

一、4中写入文本的方式&#xff1a; //①表示清空 txt StreamWriter mytxt1 new StreamWriter("D:\\1清空.txt"); string t1 ""; mytxt1.Write(t1); mytxt1.Close(); //②表示向txt写入文本 StreamWriter mytxt2 new StreamWriter("D:…

不到200行代码,一键写出简单贪吃蛇网页游戏!附详细代码!快来看看吧!

​哈喽大家好&#xff0c;这里是大白百宝阁&#xff0c;每天分享一段小代码~ 今天要分享的是&#xff0c;不到200行代码&#xff0c;制作html版贪吃蛇&#xff0c;效果如下&#xff1a; 游戏结束后&#xff0c;还会显示&#xff1a; 代码如下&#xff1a; <!DOCTYPE html&g…

GitHub图床

GitHub图床 文章目录 GitHub图床图床介绍Github访问GitHub手动修改hostsgithub520 加速器创建账户创建仓库创建token PicGoTypora 图床介绍 图床 存放图片的地方 为什么设置图床呢 在我认识图床之前, 有一个问题 [^放在typora上面的图片, 其实是一个链接, 并且将图片存放在本地…

Java之枚举

目录 枚举 引入 定义 代码示例 常用方法 代码示例 枚举的优缺点 枚举和反射 面试题 枚举 引入 枚举是在JDK1.5以后引入的。主要用途是&#xff1a;将一组常量组织起来&#xff0c;在这之前表示一组常量通常使用定义常量的方式&#xff1a; publicstaticintfinalRED1;…

树莓派通过串口驱动SU-03T语音模块

树莓派通过串口驱动SU-03T语音模块 文章目录 树莓派通过串口驱动SU-03T语音模块一、SU-03T语音模块的配置和烧录1.1 PIN引脚配置&#xff1a;1.2 设置唤醒词&#xff1a;1.3 设置控制详情&#xff1a;1.4 下载SDK并烧录到语音模块&#xff1a; 二、测试语音模块三、树莓派通过串…

汇舸环保从北交所转战港交所:狂分红超8000万,客户依赖度越来越高

《港湾商业观察》施子夫 7月31日&#xff0c;上海汇舸环保科技集团股份有限公司&#xff08;以下简称&#xff0c;汇舸环保&#xff09;递表港交所获受理&#xff0c;联席保荐机构中信证券和中国银河证券。 8月14日&#xff0c;公司披露公告称&#xff0c;另委任法国巴黎证券…