前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dubbo 技术详解,我非常喜欢Dubbo的设计

Dubbo 技术详解,我非常喜欢Dubbo的设计

原创
作者头像
疯狂的KK
修改2023-04-03 09:45:46
4690
修改2023-04-03 09:45:46
举报
文章被收录于专栏:Java项目实战

Dubbo 技术详解

Dubbo 是阿里巴巴开源的一款高性能、轻量级分布式服务框架,基于 Java 的 RPC 协议,支持多种协议和多种注册中心。其官方网站为 https://dubbo.apache.org/zh/。

本文将从以下几个方面对 Dubbo 进行详细讲解:

  • Dubbo 实现原理及代码示例
  • Dubbo 拓展协议分类及代码示例
  • Dubbo 拓展实现原理及代码示例
  • Dubbo 服务发现实现原理及代码示例

Dubbo 实现原理及代码示例

Dubbo 实现思路主要是将服务提供者发布到注册中心,消费者通过相应的接口调用服务,并通过 Dubbo 进行远程调用。

Dubbo 的实现,可以按照下面几个层次进行划分,如下图所示[1]:

  • Service 层:服务接口层,该层是服务消费者和服务提供者都需要实现的,主要是定义服务接口和方法。
代码语言:javascript
复制
public interface HelloService {

    String sayHello(String name);

}
  • Config 层:配置层,主要负责 Dubbo 的配置,如各协议配置默认值、服务提供者和服务消费者配置等。
代码语言:javascript
复制
<dubbo:application name="dubbo-demo-consumer" />
<dubbo:registry address="zookeeper://127.0.0.1:2181" />

<dubbo:reference id="helloService" interface="com.example.demo.service.HelloService" />
  • Proxy 层:服务代理层,主要用于封装服务接口,实现客户端的远程调用。
代码语言:javascript
复制
public class HelloServiceProxy implements HelloService {
    private GenericService genericService;
    
    public HelloServiceProxy(GenericService genericService) {
        super();
        this.genericService = genericService;
    }
    
    @Override
    public String sayHello(String name) {
        Object result = genericService.$invoke("sayHello", new String[]{String.class.getName()}, new Object[]{name});
        return String.valueOf(result);
    }
}
  • Registry 层:注册中心层,负责服务的注册与发现。
代码语言:javascript
复制
@Service(interfaceName = "com.example.demo.service.HelloService")
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String name) {
        return "Hello, " + name + "!";
    }

}
  • Cluster 层:集群层,负责将多个服务提供者组合成一个服务提供组,并提供服务的均衡负载和容错处理。
代码语言:javascript
复制
<dubbo:service interface="com.example.demo.service.HelloService" ref="helloService">
    <dubbo:cluster loadbalance="random" />
</dubbo:service>
  • Monitor 层:监控层,负责对 RPC 调用进行监控,以便于日志输出、统计服务调用次数等。
代码语言:javascript
复制
<dubbo:service interface="com.example.demo.service.HelloService" ref="helloService">
    <dubbo:monitor protocol="registry" />
</dubbo:service>
  • Protocol 层:协议层,主要是定义 RPC 调用的格式和方式,Dubbo 支持多种协议,如 dubbo 协议、rmi 协议、hessian 协议等。
代码语言:javascript
复制
public class HelloServiceProtocol implements Protocol {

    @Override
    public int getDefaultPort() {
        return 8080;
    }

    @Override
    public Exporter export(Invoker invoker) throws RpcException {
        return null;
    }

    @Override
    public Invoker refer(Class type, URL url) throws RpcException {
        if (GenericService.class.equals(type)) {
            return new HelloServiceInvoker(type, url);
        }
        return null;
    }

    @Override
    public void destroy() {

    }

}
  • Filter 层:过滤器层,负责在 RPC 调用前后进行一些预处理工作,如权限校验、数据加密解密等。
代码语言:javascript
复制
public class LogFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String serviceName = invoker.getInterface().getSimpleName();
        String methodName = invocation.getMethodName();

        long start = System.currentTimeMillis();
        Result result = invoker.invoke(invocation);
        long end = System.currentTimeMillis();
        LOG.info("Invoke {}.{}, dataSize:{}, time:{}ms", serviceName, methodName, result.getData().length, end - start);

        return result;
    }

}
  • Invoker 层:调用层,负责将服务接口和协议组合为一个可执行的对象,并提供服务的执行方法。
代码语言:javascript
复制
public class HelloServiceInvoker<T> extends AbstractInvoker<T> {

    public HelloServiceInvoker(Class<T> type, URL url) {
        super(type, url);
    }

    @Override
    protected Result doInvoke(Invocation invocation) throws Throwable {
        String methodName = invocation.getMethodName();
        Object[] arguments = invocation.getArguments();

        if ("sayHello".equals(methodName)) {
            String name = (String) arguments[0];
            String result = "Hello, " + name + "!";
            return new RpcResult(result);
        }

        return new RpcResult();
    }

}
  • Extension 层:扩展层,通过 SPI 机制来支持 Dubbo 的扩展,如负载均衡、序列化、压缩等。
代码语言:javascript
复制
// 在 resources/META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance 文件中配置名称为 "random" 的 LoadBalance 实现类。
@SPI("random")
public interface LoadBalance {

    /**
     * Select one invoker in list.
     * <p>
     *     随机选择一个服务提供者调用。
     * </p>
     *
     * @param invokers   invokers.
     * @param url        refer url
     * @param invocation invocation.
     * @return selected invoker.
     * @throws RpcException 当发生异常时抛出。
     */
    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;

}

Dubbo 拓展协议分类及代码示例

Dubbo 支持的协议包括:

  • Dubbo 协议:用于服务之间的通信。
代码语言:javascript
复制
<!-- 使用 dubbo 协议暴露服务 -->
<dubbo:protocol name="dubbo" port="12345" />

<!-- 使用 dubbo 协议引用服务 -->
<dubbo:reference interface="com.example.demo.service.HelloService" protocol="dubbo" />
  • RMI 协议:使用 Java 的 RMI(Remote Method Invocation)机制进行通<!-- 使用 rmi 协议暴露服务 --> <dubbo:protocol name="rmi" port="1099" /> <!-- 使用 rmi 协议引用服务 --> <dubbo:reference interface="com.example.demo.service.HelloService" protocol="rmi" />
  • Hessian 协议:使用 Hessian 进行序列化和反序列化,适合传输较小的数据量。
代码语言:javascript
复制
xml复制代码<!-- 使用 hessian 协议暴露服务 -->
<dubbo:protocol name="hessian" port="8080" />

<!-- 使用 hessian 协议引用服务 -->
<dubbo:reference interface="com.example.demo.service.HelloService" protocol="hessian" />
  • HTTP 和 WebService 协议:基于 HTTP 协议进行通讯,使用 SOAP 消息格式进行数据交互。
代码语言:javascript
复制
xml复制代码<!-- 使用 http 协议暴露服务 -->
<dubbo:protocol name="http" port="8080" />

<!-- 使用 http 协议引用服务 -->
<dubbo:reference interface="com.example.demo.service.HelloService" protocol="http" />

<!-- 使用 webservice 协议暴露服务 -->
<dubbo:protocol name="webservice" port="8080" />

<!-- 使用 webservice 协议引用服务 -->
<dubbo:reference interface="com.example.demo.service.HelloService" protocol="webservice" />

Dubbo 拓展实现原理及代码示例

Dubbo 支持 SPI(Service Provider Interface)机制来进行功能拓展,其实现方式主要包括以下三点:

  • ExtensionLoader:用于加载指定接口的拓展实现。
代码语言:javascript
复制
ExtensionLoader<Filter> extensionLoader = ExtensionLoader.getExtensionLoader(Filter.class);
Filter filter = extensionLoader.getExtension("log");
Result result = filter.invoke(invoker, invocation);
  • Adaptive:通过 @Adaptive 注解使得 Dubbo 可以在运行时动态选择对应的拓展实现。
代码语言:javascript
复制
@Adaptive("loadbalance")
public interface LoadBalance {

    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;

}
  • Configurable:用于将不同服务的配置封装成 Config 对象,方便进行参数配置和管理。
代码语言:javascript
复制
@Configuration
public class DubboConfiguration {

    @Bean
    public ApplicationConfig applicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("dubbo-demo-provider");
        return applicationConfig;
    }

    @Bean
    public ProtocolConfig protocolConfig() {
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(20880);
        return protocolConfig;
    }

    @Bean
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://127.0.0.1:2181");
        return registryConfig;
    }

}

Dubbo 服务发现实现原理及代码示例

Dubbo 服务发现的实现原理是基于注册中心实现的,具体来说,Dubbo 通过注册中心将提供者的服务地址信息注册到注册中心,消费者通过注册中心获取服务提供者的地址信息,再进行调用。

在 Dubbo 中,服务发现由类org.apache.dubbo.registry.RegistryService定义,并且有三种方式进行实现:Zookeeper、Redis 和 Multicast。

其中,Zookeeper 是 Dubbo 默认的注册中心实现方式。在 Dubbo 中,服务的注册与发现是通过类org.apache.dubbo.registry.Registryorg.apache.dubbo.registry.RegistryFactory完成的。

下面是一个基于 Zookeeper 注册中心实现的服务发现示例代码:

代码语言:javascript
复制
// 配置服务注册中心地址
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://127.0.0.1:2181");

// 配置服务消费者
ReferenceConfig<HelloService> reference = new ReferenceConfig<>();
reference.setRegistry(registry);
reference.setInterface(HelloService.class);
reference.setVersion("1.0.0");

// 获取服务对象并调用方法
HelloService helloService = reference.get();
String result = helloService.sayHello("world");

在上面的示例中,首先通过RegistryConfig配置服务注册中心的地址,然后通过ReferenceConfig配置服务的消费者,包括注册中心的配置、服务接口、以及版本号等。最后获取服务对象后,就可以调用服务提供者的方法。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Dubbo 技术详解
    • Dubbo 实现原理及代码示例
      • Dubbo 拓展协议分类及代码示例
        • Dubbo 拓展实现原理及代码示例
          • Dubbo 服务发现实现原理及代码示例
          相关产品与服务
          微服务引擎 TSE
          微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档