Dubbo源码学习基础

2023-05-16

dubbo源码学习基础

  • Dubbo源码学习基础
      • Java RMI 基本概念
      • 在 Dubbo 中使用注解
      • 自定义容错策略
      • 正确加载MyFilter类
      • Dubbo可扩展机制实战
      • Dubbo的SPI机制
      • 自定义一个LoadBalance扩展
      • Dubbo 外部化配置(Externalized Configuration)
      • Spring应用快速集成Dubbo + Hystrix
      • 生成dubbo集成spring boot的应用
      • 当Dubbo遇上Arthas:排查问题的实践
      • 如何基于Dubbo实现全异步调用链
      • DUBBO协议详解
      • Dubbo Rest 让协议跑在不同的服务器上
      • dubbo2.js解决方案
      • 第一个Dubbo Filter
      • 通过QoS对服务进行动态控制
      • 优化技巧:提前if判断帮助CPU分支预测

Dubbo源码学习基础

文章来源于dubbo官网和git贡献者,结合自己理解做筛选
dubbo用户文档
dubbo blog

Java RMI 基本概念

// 在 RMI 调用中,有以下几个核心的概念:

// 通过接口进行远程调用

// 通过客户端的 Stub 对象和服务端的 Skeleton 对象的帮助将远程调用伪装成本地调用

// 通过 RMI 注册服务完成服务的注册和发现

// 服务端的服务注册
Hello obj = new HelloImpl(); // #1
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0); // #2
Registry registry = LocateRegistry.createRegistry(1099); // #3
registry.rebind("Hello", stub); // #4
// 说明:

// 初始化服务对象实例,
// 通过 UnicastRemoteObject.exportObject 生成可以与服务端通讯的 Stub 对象,
// 创建一个本地的 RMI 注册服务,监听端口为 1099。该注册服务运行在服务端,也可以单独启动一个注册服务的进程,
// 将 Stub 对象绑定到注册服务上,这样,客户端可以通过 Hello 这个名字查找到该远程对象。
// 客户端的服务发现
Registry registry = LocateRegistry.getRegistry(); // #1
Hello stub = (Hello) registry.lookup("Hello"); // #2
String response = stub.sayHello(); // #3
// 说明:

// 获取注册服务实例,在本例中,由于没有传入任何参数,假定要获取的注册服务实例部署在本机,并监听在 1099 端口上,
// 从注册服务中查找服务名为 Hello 的远程对象,
// 通过获取的 Stub 对象发起一次 RMI 调用并获得结果。
// 理解 RMI 的工作原理和基本概念,对掌握现代分布式服务框架很有帮助,建议进一步的阅读 RMI 官方教材 [^1]。

// 了解 https://jameswxx.iteye.com/blog/740408

在 Dubbo 中使用注解

// 了解了 @EnableDubbo, @Service,@Reference 的作用,下面以一个实际的例子来展示如何使用 annotation 来开发 Dubbo 应用。以下的代码可以在 https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-annotation 中找到。

// 3. 服务端:组装服务提供方
// 通过 Spring 中 Java Config 的技术(@Configuration)和 annotation 扫描(@EnableDubbo)来发现、组装、并向外提供 Dubbo 的服务。

@Configuration
@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.impl")
static class ProviderConfiguration {
    @Bean // #1
    public ProviderConfig providerConfig() {
        ProviderConfig providerConfig = new ProviderConfig();
        providerConfig.setTimeout(1000);
        return providerConfig;
    }

    @Bean // #2
    public ApplicationConfig applicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("dubbo-annotation-provider");
        return applicationConfig;
    }

    @Bean // #3
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setAddress("localhost");
        registryConfig.setPort(2181);
        return registryConfig;
    }

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

// 4. 服务端:启动服务
// 在 main 方法中通过启动一个 Spring Context 来对外提供 Dubbo 服务。

public class ProviderBootstrap {
    public static void main(String[] args) throws Exception {
        new EmbeddedZooKeeper(2181, false).start(); // #1
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class); // #2
        context.start(); // #3
        System.in.read(); // #4
    }
}


// 6. 客户端:组装服务消费者
// 与 3. 服务端:组装服务提供方 类似,通过 Spring 中 Java Config 的技术(@Configuration)和 annotation 扫描(@EnableDubbo)来发现、组装 Dubbo 服务的消费者。

@Configuration
@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.action")
@ComponentScan(value = {"com.alibaba.dubbo.samples.action"})
static class ConsumerConfiguration {
    @Bean // #1
    public ApplicationConfig applicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("dubbo-annotation-consumer");
        return applicationConfig;
    }

    @Bean // #2
    public ConsumerConfig consumerConfig() {
        ConsumerConfig consumerConfig = new ConsumerConfig();
        consumerConfig.setTimeout(3000);
        return consumerConfig;
    }

    @Bean // #3
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setAddress("localhost");
        registryConfig.setPort(2181);
        return registryConfig;
    }
}

自定义容错策略

// 如果上述内置的容错策略无法满足你的需求,还可以通过扩展的方式来实现自定义容错策略。

// 扩展接口

com.alibaba.dubbo.rpc.cluster.Cluster

// 扩展配置

<dubbo:service cluster="xxx" />

// 扩展示例

// 下面通过一个例子来展示如何使用自定义的容错策略。 Maven 项目结构:

src
 |-main
    |-java
        |-com
            |-xxx
                |-XxxCluster.java (实现Cluster接口)
    |-resources
        |-META-INF
            |-dubbo
                |-org.apache.dubbo.rpc.cluster.Cluster (纯文本文件,内容为:xxx=com.xxx.XxxClus
                
// XxxCluster.java:

package com.xxx;
 
import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;

import java.util.List;

public class XxxCluster implements Cluster {

    @Override
    public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
        return new AbstractClusterInvoker<T>() {
            @Override
            protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
                // your custimzed fault tolarence strategy goes here
            }
        };
    }

}


// META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.Cluster文件的内容为

xxx=com.xxx.XxxCluster


各种策略对比
下表对各种策略做一个简单对比,

策略名称	优点	缺点	主要应用场景
Failover	对调用者屏蔽调用失败的信息	增加RT,额外资源开销,资源浪费	对调用rt不敏感的场景
Failfast	业务快速感知失败状态进行自主决策	产生较多报错的信息	非幂等性操作,需要快速感知失败的场景
Failsafe	即使失败了也不会影响核心流程	对于失败的信息不敏感,需要额外的监控	旁路系统,失败不影响核心流程正确性的场景
Failback	失败自动异步重试	重试任务可能堆积	对于实时性要求不高,且不需要返回值的一些异步操作
Forking	并行发起多个调用,降低失败概率	消耗额外的机器资源,需要确保操作幂等性	资源充足,且对于失败的容忍度较低,实时性要求高的场景
Broadcast	支持对所有的服务提供者进行操作	资源消耗很大	通知所有提供者更新缓存或日志等本地资源信息

正确加载MyFilter类

com.alibaba.dubbo.rpc.Filter接口除了要继承自org.apache.dubbo.rpc.Filter以外,其唯一的方法invoke也需要做特殊处理。我们看看它的方法签名:

Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;

这里参数、返回值、异常都会被实现类MyFilter用到,因此这些类也需要有兼容类;而参数、返回值不同,对于接口来说是不同的方法,因此:

// 需要在com.alibaba.dubbo.rpc.Filter里,定义老的invoke方法,MyFilter会覆盖这个方法;
// org.apache.dubbo.rpc.Filter里的invoke方法,需要找一个地方来实现桥接,框架调用Filter链执行到新的invoke方法时,新的参数如何转换成老参数,老返回值如何转换成新的返回值;

// 这里就用到了JDK8的新特性:接口default方法。

@Deprecated
public interface Filter extends org.apache.dubbo.rpc.Filter {

    Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;

    default org.apache.dubbo.rpc.Result invoke(org.apache.dubbo.rpc.Invoker<?> invoker,
                                               org.apache.dubbo.rpc.Invocation invocation)
            throws org.apache.dubbo.rpc.RpcException {
        Result.CompatibleResult result = (Result.CompatibleResult) invoke(new Invoker.CompatibleInvoker<>(invoker),
                new Invocation.CompatibleInvocation(invocation));
        return result.getDelegate();
    }
}

// 可以看到,default方法里,对参数进行了包装,然后调用老的invoke方法,并将返回值进行解包后返回给Dubbo框架。这里Result.CompatibleResult、Invocation.CompatibleInvocation以及Invoker.CompatibleInvoker都用到了代理模式。

// 感兴趣的同学可以详细看一下以下几个类:

com.alibaba.dubbo.rpc.Invocation
com.alibaba.dubbo.rpc.Invoker
com.alibaba.dubbo.rpc.Result


Dubbo可扩展机制实战

http://dubbo.apache.org/zh-cn/blog/introduction-to-dubbo-spi.html

Dubbo的SPI机制

Java SPI的使用很简单。也做到了基本的加载扩展点的功能。但Java SPI有以下的不足:

  • 需要遍历所有的实现,并实例化,然后我们在循环中才能找到我们需要的实现。
  • 配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。
  • 扩展如果依赖其他的扩展,做不到自动注入和装配
  • 不提供类似于Spring的IOC和AOP功能
    扩展很难和其他的框架集成,比如扩展里面依赖了一个Spring bean,原生的Java SPI不支持

SPI应付一些简单的场景是可以的,但对于Dubbo,它的功能还是比较弱的。Dubbo对原生SPI机制进行了一些扩展。接下来,我们就更深入地了解下Dubbo的SPI机制。

自定义一个LoadBalance扩展

本节中,我们通过一个简单的例子,来自己实现一个LoadBalance,并把它集成到Dubbo中。我会列出一些关键的步骤和代码,也可以从这个地址(https://github.com/vangoleo/dubbo-spi-demo)下载完整的demo。

到此,我们从Java SPI开始,了解了Dubbo SPI 的基本概念,并结合了Dubbo中的LoadBalance加深了理解。最后,我们还实践了一下,创建了一个自定义LoadBalance,并集成到Dubbo中。相信通过这里理论和实践的结合,大家对Dubbo的可扩展有更深入的理解。 总结一下,Dubbo SPI有以下的特点:

  • 对Dubbo进行扩展,不需要改动Dubbo的源码
  • 自定义的Dubbo的扩展点实现,是一个普通的Java类,Dubbo没有引入任何Dubbo特有的元素,对代码侵入性几乎为零。
  • 将扩展注册到Dubbo中,只需要在ClassPath中添加配置文件。使用简单。而且不会对现有代码造成影响。符合开闭原则。
    dubbo的扩展机制设计默认值:@SPI(“dubbo”) 代表默认的spi对象
  • Dubbo的扩展机制支持IoC,AoP等高级功能
  • Dubbo的扩展机制能很好的支持第三方IoC容器,默认支持Spring - Bean,可自己扩展来支持其他容器,比如Google的Guice。
  • 切换扩展点的实现,只需要在配置文件中修改具体的实现,不需要改代码。使用方便。

Dubbo 外部化配置(Externalized Configuration)

// 外部化配置文件
// 将以下内容的外部化配置文件物理路径为:classpath:/META-INF/config.properties:

# 单 Dubbo 配置 Bean 绑定
## application
dubbo.application.id = applicationBean
dubbo.application.name = dubbo-demo-application

## module
dubbo.module.id = moduleBean
dubbo.module.name = dubbo-demo-module

## registry
dubbo.registry.address = zookeeper://192.168.99.100:32770

## protocol
dubbo.protocol.name = dubbo
dubbo.protocol.port = 20880

## monitor
dubbo.monitor.address = zookeeper://127.0.0.1:32770

## provider
dubbo.provider.host = 127.0.0.1

## consumer
dubbo.consumer.client = netty

# @EnableDubboConfig 配置 Bean

/**
 * Dubbo 配置 Bean
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 */
@EnableDubboConfig
@PropertySource("META-INF/config.properties")
@Configuration
public class DubboConfiguration {

}

/**
 * Dubbo 配置引导类
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 */
public class DubboConfigurationBootstrap {

    public static void main(String[] args) {
        // 创建配置上下文
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 注册当前配置 Bean
        context.register(DubboConfiguration.class);
        context.refresh();
 	    // application
        ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
        System.out.printf("applicationBean.name = %s \n", applicationConfig.getName());

        // module
        ModuleConfig moduleConfig = context.getBean("moduleBean", ModuleConfig.class);
        System.out.printf("moduleBean.name = %s \n", moduleConfig.getName());

        // registry
        RegistryConfig registryConfig = context.getBean(RegistryConfig.class);
        System.out.printf("registryConfig.name = %s \n", registryConfig.getAddress());

        // protocol
        ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class);
        System.out.printf("protocolConfig.name = %s \n", protocolConfig.getName());
        System.out.printf("protocolConfig.port = %s \n", protocolConfig.getPort());

        // monitor
        MonitorConfig monitorConfig = context.getBean(MonitorConfig.class);
        System.out.printf("monitorConfig.name = %s \n", monitorConfig.getAddress());

        // provider
        ProviderConfig providerConfig = context.getBean(ProviderConfig.class);
        System.out.printf("providerConfig.name = %s \n", providerConfig.getHost());

        // consumer
        ConsumerConfig consumerConfig = context.getBean(ConsumerConfig.class);
        System.out.printf("consumerConfig.name = %s \n", consumerConfig.getClient());
    }
}

// 执行结果

applicationBean.name = dubbo-demo-application 
moduleBean.name = dubbo-demo-module 
registryConfig.name = zookeeper://192.168.99.100:32770 
protocolConfig.name = dubbo 
protocolConfig.port = 20880 
monitorConfig.name = zookeeper://127.0.0.1:32770 
providerConfig.name = 127.0.0.1 
consumerConfig.name = netty

// 不难发现,@EnableDubboConfig 配置 Bean 配合外部化文件 classpath:/META-INF/config.properties,与执行输出内容相同。

Spring应用快速集成Dubbo + Hystrix

// Hystrix 旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能。

// Dubbo是Alibaba开源的,目前国内最流行的java rpc框架。

// 本文介绍在spring应用里,怎么把Dubbo和Hystrix结合起来使用。

https://github.com/Netflix/Hystrix
https://github.com/apache/incubator-dubbo

// Spring Boot应用

// Demo地址:
https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-spring-boot-hystrix

生成dubbo集成spring boot的应用

//  对于不熟悉dubbo 集成spring boot应用的同学,可以在这里直接生成dubbo + spring boot的工程: http://start.dubbo.io/

// 配置spring-cloud-starter-netflix-hystrix

// spring boot官方提供了对hystrix的集成,直接在pom.xml里加入依赖:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>1.4.4.RELEASE</version>
        </dependency>

// 然后在Application类上增加@EnableHystrix来启用hystrix starter:

@SpringBootApplication
@EnableHystrix
public class ProviderApplication {


// 配置Provider端
// 在Dubbo的Provider上增加@HystrixCommand配置,这样子调用就会经过Hystrix代理。

@Service(version = "1.0.0")
public class HelloServiceImpl implements HelloService {
    @HystrixCommand(commandProperties = {
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") })
    @Override
    public String sayHello(String name) {
        // System.out.println("async provider received: " + name);
        // return "annotation: hello, " + name;
        throw new RuntimeException("Exception to show hystrix enabled.");
    }
}

// 配置Consumer端
// 对于Consumer端,则可以增加一层method调用,并在method上配置@HystrixCommand。当调用出错时,会走到fallbackMethod = "reliable"的调用里。

    @Reference(version = "1.0.0")
    private HelloService demoService;

    @HystrixCommand(fallbackMethod = "reliable")
    public String doSayHello(String name) {
        return demoService.sayHello(name);
    }
    public String reliable(String name) {
        return "hystrix fallback value";
    }
// 通过上面的配置,很简单地就完成了Spring Boot里Dubbo + Hystrix的集成

当Dubbo遇上Arthas:排查问题的实践

// Arthas 是基于 Greys 进行二次开发的全新在线诊断工具,利用Java6的Instrumentation特性,动态增强你所指定的类,获取你想要到的信息, 采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,让你在定位、分析诊断问题时看每一个操作都看起来是那么的 

https://github.com/apache/incubator-dubbo-website/blob/asf-site/blog/zh-cn/dubbo-meet-arthas.md

如何基于Dubbo实现全异步调用链

https://github.com/apache/incubator-dubbo-website/blob/asf-site/blog/zh-cn/dubbo-new-async.md

// 基于Dubbo实现全异步编程,是在2.7.0版本中对现有异步方式增强后新引入的功能。本文先是回顾2.6.x及之前版本对异步的支持情况及存在的问题,引出了2.7.0版本基于CompletableFuture做了哪些针对性的增强,通过几个示例详细阐述了增强后的异步编程的使用方式,最后总结了引入异步模式带来的新问题及Dubbo的解决方法。通过阅读这篇文章,可以很容易的基于Dubbo2.7.0+版本实现一个全异步的远程服务调用链路。

DUBBO协议详解

https://github.com/apache/incubator-dubbo-website/blob/asf-site/blog/zh-cn/dubbo-protocol.md

Dubbo Rest 让协议跑在不同的服务器上

// 目前 REST 协议在 Dubbo 中可以跑在五种不同的 server 上,分别是:

"netty": 直接基于 netty 框架的 rest server,通过 <dubbo:protocol name="rest" server="netty"/> 来配置
"tomcat": 基于嵌入式 tomcat 的 rest server,通过 <dubbo:protocol name="rest" server="tomcat"/> 来配置
"jetty": 默认选项,基于嵌入式 jetty 的 rest server,通过 <dubbo:protocol name="rest" server="jetty"/> 来配置
"sunhttp": 使用 JDK 内置的 Sun HTTP server 作为 rest server,通过 <dubbo:protocol name="rest" server="sunhttp"/> 来配置,仅推荐在开发环境中使用
"servlet”: 采用外部应用服务器的 servlet 容器来做 rest server,这个时候,除了配置 <dubbo:protocol name="rest" server="servlet"/> 之外,还需要在 web.xml 中做额外的配置
// 由于以上的例子展示了 "netty" 作为 rest server,下面演示一下使用嵌入式 tomcat 的 rest server 的用法。

// 注:本章节讨论的示例可以通过 https://github.com/beiwei30/dubbo-rest-samples/tree/master/tomcat 来获得

// 增加 Tomcat 相关的依赖
    <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-logging-juli</artifactId>
        </dependency>
// 配置 protocol 使用 tomcat 作为 REST server

<dubbo:protocol name="rest" port="8080" server="tomcat"/>

// 使用外部的 Servlet 容器

// 进一步的,还可以使用外部的 servlet 容器来启动 Dubbo 的 REST 服务。

// 注:本章节讨论的示例可以通过 https://github.com/beiwei30/dubbo-rest-samples/tree/master/servlet 来获得

// 1. 修改 pom.xml 改变打包方式
因为使用的是外部的 servlet 容器,需要将打包方式修改为 "war"

    <packaging>war</packaging>
// 2. 修改 rest-provider.xml
// 配置 "server" 为 "servlet" 表示将使用外部的 servlet 容器。并配置 "contextpath" 为 "",原因是在使用外部 servlet 容器时,Dubbo 的 REST 支持需要知道被托管的 webapp 的 contextpath 是什么。这里我们计划通过 root context path 来部署应用,所以配置其为 ""。

    <dubbo:protocol name="rest" port="8080" server="servlet" contextpath=""/>

// 3. 配置 WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <context-param> <!-- #1 -->
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/spring/rest-provider.xml</param-value>
    </context-param>

    <listener>
        <listener-class>com.alibaba.dubbo.remoting.http.servlet.BootstrapListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet> <!-- #2 -->
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
    
// 配置 Dubbo 和 Spring 相关的 ContextListener,打开 Dubbo HTTP 支持,以及通过 rest-provider.xml 来装配 Dubbo 服务
// 配置 Dubbo HTTP 所需的 DiapatcherServlet
// 这样做之后,不再需要 RestProvider 来启动 Dubbo 服务,可以将其从工程中删掉。对应的,现在 Dubbo 的服务将会随着 Servlet 容器的启动而启动。启动完毕之后,可以通过类似 "http://localhost:8080/api/users/1" 来访问暴露出的 REST 服务。需要注意的是,这个例子里假定了服务提供方的 WAR 包部署在 root context path 上,所以当该应用通过 IDE 配置的 tomcat server 启动时,需要指定 Application Context 为 "/"。

// 增加 Swagger 支持
// 在上面使用外部 Servlet 容器的例子的基础上,讨论如何暴露 Swagger OpenApi 以及如何继承 Swagger UI。

// 注:本章节讨论的示例可以通过 https://github.com/beiwei30/dubbo-rest-samples/tree/master/servlet 来获得

// 1. 暴露 Swagger OpenApi
// 增加 swagger 相关依赖,以便通过 "http://localhost:8080/openapi.json" 来访问 REST 服务的描述

    <properties>
        <swagger.version>2.0.6</swagger.version>
    </properties>

	<dependencies> 
        <dependency>
            <groupId>io.swagger.core.v3</groupId>
            <artifactId>swagger-jaxrs2</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <dependency>
            <groupId>io.swagger.core.v3</groupId>
            <artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
            <version>${swagger.version}</version>
        </dependency>
    </dependencies>
// 修改 WEB-INF/web.xml,增加 openapi servlet 的配置

<web-app>
    ...
	<servlet> <!-- #3 -->
        <servlet-name>openapi</servlet-name>
        <servlet-class>io.swagger.v3.jaxrs2.integration.OpenApiServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>openapi</servlet-name>
        <url-pattern>/openapi.json</url-pattern>
        <url-pattern>/openapi.yaml</url-pattern>
    </servlet-mapping>
</web-app>
// 重新启动应用之后,可以通过访问 "http://localhost:8080/openapi.json" 或者 "http://localhost:8080/openapi.yaml" 来访问暴露出的 openapi 的契约,以下是 yaml 格式的表述:

openapi: 3.0.1
paths:
  /api/users/{id}:
    get:
      operationId: getUser
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: integer
          format: int64
      responses:
        default:
          description: default response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
            text/xml:
              schema:
                $ref: '#/components/schemas/User'
  /api/users/register:
    post:
      operationId: registerUser
      requestBody:
        description: a user to register
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
          text/xml:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        default:
          description: default response
          content:
            application/json:
              schema:
                type: integer
                format: int64
            text/xml:
              schema:
                type: integer
                format: int64
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
// 2. 集成 Swagger UI
// 在 pom.xml 中继续增加 swagger-ui 的依赖,这里使用的是 webjars 的版本,从集成的角度来说更加简洁。webjars 的工作机制可以参阅 webjars 官网 ^6

    <properties>
        <swagger.webjar.version>3.20.3</swagger.webjar.version>
    </properties>
    <dependencies> 
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>swagger-ui</artifactId>
            <version>${swagger.webjar.version}</version>
        </dependency>
    </dependencies>
// 在工程的 webapp/WEB-INF 根目录下增加一个 HTML 文件,内容如下。HTML 文件名可以为任何名字,没有硬性要求,如果该文件被命名为 "swagger-ui.html",那么你可以通过访问 “http://localhost:8080/swagger-ui.html" 来访问 swagger UI。本例为了演示方便起见,将其命名为 "index.html",这样当访问 "http://localhost:8080" 时,就可以很方便的得到 swagger UI 的页面。

// 本文没有涉及的内容包含但不限于国际化支持、Dubbo REST 更高阶的注入扩展的用法、以及 Dubbo REST 支持未来的规划。其中 Dubbo REST 扩展的支持可以参考 https://github.com/beiwei30/dubbo-rest-samples/tree/master/extensions 中的演示

dubbo2.js解决方案

// 为了让对 dubbo2.js 感兴趣的读者有一个直观的体验,本节呈现一个快速入门示例,让你体会到使用 dubbo2.js 调用 dubbo 服务是一件多么轻松的事。

https://github.com/apache/incubator-dubbo-website/blob/asf-site/blog/zh-cn/dubbo2-js.md

https://github.com/dubbo/dubbo2.js

第一个Dubbo Filter

// 在Dubbo的整体设计中,Filter是一个很重要的概念,包括Dubbo本身的大多数功能,都是基于此扩展点实现的,在每次的调用过程中,Filter的拦截都会被执行。

// 此Filter记录了调用过程中的状态信息,并且通过invocation对象将客户端设置的attachments参数传递到服务端。并且在调用完成后清除这些参数,这就是为什么请求状态信息可以按次记录并且进行传递。

https://github.com/apache/incubator-dubbo-website/blob/asf-site/blog/zh-cn/first-dubbo-filter.md

通过QoS对服务进行动态控制

// QoS目前支持的命令包括:

help: 帮助命令,列出
ls: 列出当前所有的正在提供的服务,以及消费的服务
online: 动态将某个或全部服务向注册中心进行注册
offline: 动态将某个或全部服务从注册中心摘除(反注册)
quit: 退出当前telnet会话

优化技巧:提前if判断帮助CPU分支预测

// Dubbo里ChannelEventRunnable的switch判断

// 在ChannelEventRunnable里有一个switch来判断channel state,然后做对应的逻辑:查看

// 一个channel建立起来之后,超过99.9%情况它的state都是ChannelState.RECEIVED,那么可以考虑把这个判断提前

// switch对于CPU来说难以做分支预测

// 某些switch条件如果概率比较高,可以考虑单独提前if判断,充分利用CPU的分支预测机制

// https://github.com/apache/incubator-dubbo-website/blob/asf-site/blog/zh-cn/optimization-branch-prediction.md
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Dubbo源码学习基础 的相关文章

  • PX4/APM/飞控的学习笔记前言-Cxm

    开始了 开始了 终于有时间可以学习飞控了 此文章是用来当目录 我会持续更新我的学习之旅 希望能对各位有所帮助 如果有错误的地方还请各位前辈指点 此帖持续更新后续内容 其实从21年的一月就开始学习飞控一开始是从PX4开始学习 但是因为对liu

随机推荐

  • kubernetes 中文版

    这个文档非常好用 xff0c 建议收藏 无水印版 https pan baidu com s 1LSI46GBENd90Z06FnuaKmw lukb
  • SimpleBGC三轴云台用户手册

    SimpleBGC三轴云台用户手册 V1 00 硬件平台 xff1a STorM BGC V1 31 软件框架 xff1a SimpleBGC V1 00 本方案是采用俄版STorM BGC硬件平台 xff0c 软件采用SimpleBGC架
  • typedef和define有什么区别

    typedef和define都是替一个对象取一个别名 xff0c 以此增强程序的可读性 xff0c 区别如下 xff1a xff08 1 xff09 原理不同 define是C语言中定义的语法 xff0c 是预处理指令 xff0c 在预处理
  • 接口返回报错 resource notfound,plrase check path

    1 报错原因 post请求的content type application x www form urlencoded 但是请求体中设置的是json数据 34 date 34 34 2022 01 01 34 34 inclTransfe
  • Java中枚举的线程安全性及序列化问题

    一 枚举是如何保证线程安全的 要想看源码 xff0c 首先得有一个类吧 xff0c 那么枚举类型到底是什么类呢 xff1f 是enum吗 xff1f 答案很明显不是 xff0c enum就和class一样 xff0c 只是一个关键字 xff
  • Vscode配置Git

    vscode安装git 首先我们要确保我们下载了vscode和git xff0c 接下来就是给vscode配置git的步骤 xff1a 配置git环境变量 xff08 path值为git安装位置的cmd文件夹 xff09 xff0c 如图
  • SLAM-6视觉里程计里面特征点计算的缺点所做的改进

    缺点的改进方法 xff1a 由于之前的视觉里程计要计算关键点和描述子 xff0c 花费大量的时间 xff0c 有两种办法可以避免 1 只计算关键点 xff0c 通过光流法追踪关键点的运动 xff0c 可以得到同一个关键点在不同时刻图片的位置
  • SLAM8-后端的其他方法,BA与图优化,Pose Graph优化的理论与公式详解、因子图优化

    1 BA方法 Bundle Adjustment翻译过来是 光束调整 xff0c 意思是每个特征反射的光束 xff0c 通过调整它们的空间位置和相机姿态 xff0c 使它们都汇聚到相机光心 xff0c 这个过程叫BA 假定世界坐标系下的点p
  • 【动手学深度学习】 2预备知识

    李沫 动手学习深度学习 课程学习 需要预备的知识原因重点线性代数处理表格数据矩阵运算微积分决定以何种方式调整参数 损失函数 xff08 loss function xff09 衡量 模型有多糟糕 这个问题的分数 梯度 xff08 gradi
  • JDK源码之-java.lang.Object

    JDK源码之 java lang Object public final native Class lt gt getClass public native int hashCode public boolean equals Object
  • Apm飞控学习笔记之-电机解锁和故障保护-Cxm

    前言 CSDN https mp csdn net mp blog creation editor 122115245 这边说的解锁是指的非自动解锁和地面站解锁 常规解锁流程 61 安全开关 gt 内八解锁 这一篇会介绍整个解锁流程以及飞控
  • https://gns3.com/community/discussion/gns3-doesn-t-work-on-vmware-play

    swered Question GNS3 doesn t work on VMWARE player 15 Hi guys today I try to install GNS3 on new VMWARE player 15 with V
  • 基于stm32的数控线性稳压电源,恒压恒流电源资料

    基于stm32的数控线性稳压电源 xff0c 恒压恒流电源资料 极具学习和设计参考价值 xff0c 已验证 xff0c 可做实物 xff0c 送资料 xff0c 此价格仅为资料 xff0c 资料包括源程序 xff0c 原理图 xff0c p
  • Docker安装Elasticsearch的遇到的那些坑

    1 根据百度到的一篇文章 https segmentfault com a 1190000004376504 下载其最新镜像 hangxin1940 docker elasticsearch cn v2 1 0 使用 docker run
  • Spring boot + Spring Security + Thymeleaf 认证失败返回错误信息

    Spring boot 43 Spring Security 43 Thymeleaf 认证失败返回错误信息 Spring boot以其众多友谊的特性 xff0c 如零配置 微服务等 xff0c 吸引了很多的粉丝 而其与Spring Sec
  • Java经典面试题(其三)——JVM原理和调优

    Java经典面试题 xff08 其三 xff09 JVM原理和调优 一 什么是JVM JVM是Java Virtual Machine xff08 Java虚拟机 xff09 的缩写 xff0c JVM是一种用于计算设备的规范 xff0c
  • Spring Boot Starter的面试题

    Spring Boot Starter的面试题 1 常见的starter会包几个方面的内容 xff1f 分别是什么 xff1f span class hljs comment 常见的starter会包括下面四个方面的内容 span span
  • 个人经历:谈一谈的程序员求职途径

    个人经历 xff1a 谈一谈的程序员求职途径 互联网招聘网站的确是五花八门 xff0c 种类繁多 xff0c 在投递简历 xff0c 接听面试电话的过程中 xff0c 要擦亮眼睛 xff0c 慎重选择和沟通 我是去年跳槽的 xff0c 下面
  • JVM调优再学习

    JVM调优再学习 堆大小设置 JVM中最大堆大小有三方面限制 xff1a 相关操作系统的数据模型 xff08 32 bit还是64 bit xff09 限制 xff1b 系统的可用虚拟内存限制 xff1b 系统的可用物理内存限制 32位系统
  • Dubbo源码学习基础

    dubbo源码学习基础 Dubbo源码学习基础Java RMI 基本概念在 Dubbo 中使用注解自定义容错策略正确加载MyFilter类Dubbo可扩展机制实战Dubbo的SPI机制自定义一个LoadBalance扩展Dubbo 外部化配