Dubbo源码解读与实战:(一)源码环境搭建

前言

搭建环境之前,先看官网介绍,大致了解Dubbo的架构思想,这个可以帮助你后面更好的了解Dubbo的基本功能以及核心角色

Registry:注册中心

          负责服务地址的注册与查找,服务Provider和Consumer只在启动时与注册中心交互。注册中心通过长连接感知Provider的存在,当Provider出现宕机时,注册中心会立即推送通知给Consumer

Provider:服务提供者

          在他启动的时候,会向Registry发送注册信息,会将自己服务的IP地址和相关配置信息封装成URL添加在zookeeper中

Consumer:服务消费着

          在他启动的时候,会向 Registry 进行订阅操作。订阅操作会从 ZooKeeper 中获取 Provider 注册的 URL,并在 ZooKeeper 中添加相应的监听器。获取到 Provider URL 之后,Consumer 会根据负载均衡算法从多个 Provider 中选择一个 Provider 并与其建立连接,最后发起对 Provider 的 RPC 调用。 如果 Provider URL 发生变更,Consumer 将会通过之前订阅过程中在注册中心添加的监听器,获取到最新的 Provider URL 信息,进行相应的调整,比如断开与宕机 Provider 的连接,并与新的 Provider 建立连接。Consumer 与 Provider 建立的是长连接,且 Consumer 会缓存 Provider 信息,所以一旦连接建立,即使注册中心宕机,也不会影响已运行的 Provider 和 Consumer。

Monitor:监控中心

         用于统计服务的调用次数和调用时间。Provider 和 Consumer 在运行过程中,会在内存中统计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。监控中心在上面的架构图中并不是必要角色,监控中心宕机不会影响 Provider、Consumer 以及 Registry 的功能,只会丢失监控数据而已。

搭建源码环境

Dobbo源码已经开源,地址 https://github.com/apache/dubbo

我们可以将源码fork到自己仓库,再下载到本地,dobbo是通过maven编译打包的,成功之后如下图:

下面简单介绍一下dubbo的核心模块:这个源码主要是在dubbo2.7x版本,请切换到此版本。

dubbo-common 模块:

              Dubbo的公共模块,主要是一些工具类和一些公共逻辑,例如后面紧接着要介绍的 Dubbo SPI 实现、时间轮实现、动态编译器等。

dubbo-remoting 模块:

Dubbo 的远程通信模块,其中的子模块依赖各种开源组件实现远程通信。在 dubbo-remoting-api 子模块中定义该模块的抽象概念,在其他子模块中依赖其他开源组件进行实现,例如,dubbo-remoting-netty4 子模块依赖 Netty 4 实现远程通信,dubbo-remoting-zookeeper 通过 Apache Curator 实现与 ZooKeeper 集群的交互。

dubbo-rpc 模块:

Dubbo 中对远程调用协议进行抽象的模块,其中抽象了各种协议,依赖于 dubbo-remoting 模块的远程调用功能。dubbo-rpc-api 子模块是核心抽象,其他子模块是针对具体协议的实现,例如,dubbo-rpc-dubbo 子模块是对 Dubbo 协议的实现,依赖了 dubbo-remoting-netty4 等 dubbo-remoting 子模块。 dubbo-rpc 模块的实现中只包含一对一的调用,不关心集群的相关内容。

dubbo-cluster 模块:

Dubbo 中负责管理集群的模块,提供了负载均衡、容错、路由等一系列集群相关的功能,最终的目的是将多个 Provider 伪装为一个 Provider,这样 Consumer 就可以像调用一个 Provider 那样调用 Provider 集群了。

dubbo-registry 模块:

Dubbo 中负责与多种开源注册中心进行交互的模块,提供注册中心的能力。其中, dubbo-registry-api 子模块是顶层抽象,其他子模块是针对具体开源注册中心组件的具体实现,例如,dubbo-registry-zookeeper 子模块是 Dubbo 接入 ZooKeeper 的具体实现。

dubbo-monitor 模块:

Dubbo 的监控模块,主要用于统计服务调用次数、调用时间以及实现调用链跟踪的服务。

dubbo-config 模块:

Dubbo 对外暴露的配置都是由该模块进行解析的。例如,dubbo-config-api 子模块负责处理 API 方式使用时的相关配置,dubbo-config-spring 子模块负责处理与 Spring 集成使用时的相关配置方式。有了 dubbo-config 模块,用户只需要了解 Dubbo 配置的规则即可,无须了解 Dubbo 内部的细节。

dubbo-metadata 模块:

Dubbo 的元数据模块(后续会详细介绍元数据的内容)。dubbo-metadata 模块的实现套路也是有一个 api 子模块进行抽象,然后其他子模块进行具体实现。

dubbo-configcenter 模块:

Dubbo 的动态配置模块,主要负责外部化配置以及服务治理规则的存储与通知,提供了多个子模块用来接入多种开源的服务发现组件。

Dubbo 源码中的 Demo 示例

 

      dubbo-demo-interface:

              在使用 Dubbo 之前,你还需要一个业务接口,这个业务接口可以认为是 Dubbo Provider 和 Dubbo Consumer 的公约,反映出很多信息:这个接口模块就是定义接口模块。生成和消费服务都要依赖这个模块。

      dubbo-demo-api:

          不能依赖于 Spring 框架,只能使用 API 来构建 Dubbo Provider 和 Consumer,比较典型的一种场景就是在写 SDK 的时候。

         下面是dubbo-demo-api-provider 模块,main入口方向。

private static void startWithBootstrap() {
        // 创建一个ServiceConfig的实例,泛型参数是业务接口实现类,
        // 即DemoServiceImpl
        ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();
        // 指定业务接口
        service.setInterface(DemoService.class);
        // 指定业务接口的实现,由该对象来处理Consumer的请求
        service.setRef(new DemoServiceImpl());
        // 获取DubboBootstrap实例,这是个单例的对象
        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
        //生成一个 ApplicationConfig 的实例、指定ZK地址以及ServiceConfig实例
        bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider"))
                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
                .service(service)
                .start()
                .await();
    }

               这里,同样会有一个 DemoServiceImpl 实现了 DemoService 接口,并且在 org.apache.dubbo.demo.provider 目录下,能被扫描到,暴露成 Dubbo 服务。

         在看看dobbo-demo-api-comsummer模块,main入口方法怎么去通过注册中心获取生产者信息再去调用

private static void runWithBootstrap() {
        // 创建ReferenceConfig,其中指定了引用的接口DemoService
        ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
        reference.setInterface(DemoService.class);
        reference.setGeneric("true");

        // 创建DubboBootstrap,指定ApplicationConfig以及RegistryConfig
        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
        bootstrap.application(new ApplicationConfig("dubbo-demo-api-consumer"))
                .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
                .reference(reference)
                .start();

        // 获取DemoService实例并调用其方法
        DemoService demoService = ReferenceConfigCache.getCache().get(reference);
        String message = demoService.sayHello("dubbo man");
        System.out.println(message);

        // generic invoke
        GenericService genericService = (GenericService) demoService;
        Object genericInvokeResult = genericService.$invoke("sayHello", new String[] { String.class.getName() },
                new Object[] { "dubbo generic invoke" });
        System.out.println(genericInvokeResult);
    }

      dubbo-demo-xml:

        在 消费服务的resource/spring/dubbo-consumer.xml 配置文件中,会指定注册中心地址(就是前面 ZooKeeper 的地址),这样 Dubbo 才能从 ZooKeeper 中拉取到 Provider 暴露的服务列表信息

<beans>
    <dubbo:application name="demo-consumer"/>
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:reference id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService"/>
</beans>

        在生成服务的resource/spring/dubbo-provider.xml配置文件,配置了相关信息。

<?xml version="1.0" encoding="UTF-8"?>
    <dubbo:application metadata-type="remote" name="demo-provider"/>
    <dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:protocol name="dubbo"/>
    <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
    <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/>
</beans>

      dubbo-demo-annotation:

      注解模块就是把xml的转换成注解。大致和xml差不多。

public class Application { 
    public static void main(String[] args) throws Exception { 
	    // 使用AnnotationConfigApplicationContext初始化Spring容器, 
        // 从ProviderConfiguration这个类的注解上拿相关配置信息 
        AnnotationConfigApplicationContext context =  
              new AnnotationConfigApplicationContext( 
                  ProviderConfiguration.class); 
        context.start(); 
        System.in.read(); 
    } 
    @Configuration // 配置类 
    // @EnableDubbo注解指定包下的Bean都会被扫描,并做Dubbo服务暴露出去 
    @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")      
    // @PropertySource注解指定了其他配置信息 
    @PropertySource("classpath:/spring/dubbo-provider.properties")      
    static class ProviderConfiguration { 
        @Bean 
        public RegistryConfig registryConfig() { 
            RegistryConfig registryConfig = new RegistryConfig(); 
            registryConfig.setAddress("zookeeper://127.0.0.1:2181"); 
            return registryConfig; 
        } 
    } 
} 

      这里,同样会有一个 DemoServiceImpl 实现了 DemoService 接口,并且在 org.apache.dubbo.demo.provider 目录下,能被扫描到,暴露成 Dubbo 服务。

     接着再来看 dubbo-demo-annotation-consumer 模块,其中 Application 中也是通过 AnnotationConfigApplicationContext 初始化 Spring 容器,也会扫描指定目录下的 Bean,会扫到 DemoServiceComponent 这个 Bean,其中就通过 @Reference 注解注入 Dubbo 服务相关的 Bean

@Component("demoServiceComponent") 
public class DemoServiceComponent implements DemoService { 
    @Reference // 注入Dubbo服务 
    private DemoService demoService; 
    @Override 
    public String sayHello(String name) { 
        return demoService.sayHello(name); 
    } 
	  // 其他方法 
}

下一节:Dubbo源码解读与实战:(二)Dubbo 的配置总线:抓住 URL,就理解了半个 Dubbo

猜你喜欢

转载自blog.csdn.net/shrek11/article/details/108093093