1.分布式 简介

尚硅谷-dubbo.docx

1. 什么是分布式系统

《分布式系统原理与范型》定义:
“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”
分布式系统(distributed system)是建立在网络之上的软件系统。
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。

2. 发展演变

1. 单一架构

当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
image.png

2. 垂直应用架构

当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
image.png

3. 分布式系统架构

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
image.png

4. 流动计算架构

当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)[ Service Oriented Architecture]是关键
image.png

3. RPC

1. 什么是RPC

RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,

2. 基本原理

image.png

2. Dubbo核心概念

1.简介

Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
官网:
http://dubbo.apache.org/
image.png
服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者(Consumer): 调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
Ø 调用关系说明
l 服务容器负责启动,加载,运行服务提供者。
l 服务提供者在启动时,向注册中心注册自己提供的服务。
l 服务消费者在启动时,向注册中心订阅自己所需的服务。
l 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
l 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
l 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

2. Dubbo环境搭建

1. Zookeeper 集群搭建

image.png

2. 安装dubbo-admin管理控制台

dubbo本身并不是一个服务软件。它其实就是一个jar包能够帮你的java程序连接到zookeeper,并利用zookeeper消费、提供服务。所以你不用在Linux上启动什么dubbo服务。
但是为了让用户更好的管理监控众多的dubbo服务,官方提供了一个可视化的监控程序,不过这个监控即使不装也不影响使用。

1、下载dubbo-admin

https://github.com/apache/incubator-dubbo-ops
image.png

2、进入目录,修改dubbo-admin配置

image.png

3. 重新打包

mvc clean package

4. 运行dubbo-admin

image.png

3. 项目实践

1. 要求

建议将服务接口,服务模型,服务异常等均放在 API 包中,因为服务模型及异常也是 API 的一部分,同时,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。
如果需要,也可以考虑在 API 包中放置一份 spring 的引用配置,这样使用方,只需在 spring 加载过程中引用此配置即可,配置建议放在模块的包目录下,以免冲突,如:com/alibaba/china/xxx/dubbo-reference.xml。
image.png

2.interface公共接口层 编写(主要放接口以及bean)

1、Bean模型

  1. 1Bean模型
  2. public class UserAddress implements Serializable{
  3. private Integer id;
  4. private String userAddress;
  5. private String userId;
  6. private String consignee;
  7. private String phoneNum;
  8. private String isDefault;
  9. }

2. 接口编写

image.png

  1. public interface OrderService {
  2. public List<UserAddress> initOrder(String userId);
  3. }
  4. ==========================================
  5. public interface UserService {
  6. public List<UserAddress> getUserAddressList(String userId);
  7. }

3. gmall-user 用户模块(对用户接口的实现)

1. 导入接口模块

  1. <dependencies>
  2. <dependency>
  3. <groupId>com.atguigu.dubbo</groupId>
  4. <artifactId>gmall-interface</artifactId>
  5. <version>0.0.1-SNAPSHOT</version>
  6. </dependency>
  7. </dependencies>

2. 实现Service服务

public class UserServiceImpl implements UserService {

    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        // TODO Auto-generated method stub
        return userAddressDao.getUserAddressById(userId);
    }
}

4. gmall-order-web:订单模块(调用用户模块)

1. 导入接口模块

<dependencies>
      <dependency>
          <groupId>com.atguigu.dubbo</groupId>
          <artifactId>gmall-interface</artifactId>
          <version>0.0.1-SNAPSHOT</version>
      </dependency>
   </dependencies>

2. 实现消费方法

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    UserService userService;

    @Override
    public List<UserAddress> initOrder(String userId) {
        // TODO Auto-generated method stub
        System.out.println("用户id:"+userId);
        //1、查询用户的收货地址
        List<UserAddress> addressList = userService.getUserAddressList(userId);
        for (UserAddress userAddress : addressList) {
            System.out.println(userAddress.getUserAddress());
        }
        return addressList;
    }
}

5. 对消费者和服务者配置

1. 引入dubbo和zookeeper客服端

<!--    dubbo-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.2</version>
        </dependency>
<!--    zookeeper客服端 -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.12.0</version>
        </dependency>

2. 配置服务者暴露接口

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">


<!--    服务的的名称-->
    <dubbo:application name="user-provider"></dubbo:application>
<!--    指定注册中心位置-->
    <dubbo:registry protocol="zookeeper" address="192.168.234.100:2181,192.168.234.101:2181,192.168.234.102:2181"></dubbo:registry>
<!--    指定通讯规则-->
    <dubbo:protocol name="dubbo" port="20882"></dubbo:protocol>
<!--    暴露服务-->
    <dubbo:service interface="com.atguigu.gmall.service.UserService" ref="userServiceImpl01"></dubbo:service>
<!--         服务的实现 -->
    <bean id="userServiceImpl01" class="com.atgui.gmall.service.impl.UserServiceImpl"></bean>
</beans>

3. 配置消费者调用的远程服务接口

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       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://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <dubbo:application name="order-consumer"></dubbo:application>
    <dubbo:registry protocol="zookeeper" address="192.168.234.100:2181,192.168.234.101:2181,192.168.234.102:2181"></dubbo:registry>
<!--    声明需要调用的远程服务接口-->
    <dubbo:reference interface="com.atguigu.gmall.service.UserService" id="userService"> </dubbo:reference>
<!--    扫描注解-->
    <context:component-scan base-package="com.atguigu.gmall"></context:component-scan>
</beans>

4. 启动测试

public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("provider.xml");
        ioc.start();
        System.in.read();
    }
======================消费者================
public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("consumer.xml");
        OrderService bean = ioc.getBean(OrderService.class);
        List<UserAddress> userAddresses = bean.initOrder("1");
        System.in.read();
    }

image.png

3. 监控中心

1. dubbo-admin

打包 - 运行jar报即可
图形化的服务管理页面;安装时需要指定注册中心地址,即可从注册中心中获取到所有的提供者/消费者进行配置管理

2.dubbo-monitor-simple

简单的监控中心;

1. 安装

|

1、下载 dubbo-ops

https://github.com/apache/incubator-dubbo-ops | | —- | |

2、修改配置指定注册中心地址

进入dubbo-monitor-simple\src\main\resources\conf
修改dubbo.properties文件 | |

3、打包dubbo-monitor-simple

mvn clean package -Dmaven.test.skip=true | |

4、解压tar.gz 文件,并运行start.bat

如果缺少servlet-api,自行导入servlet-api再访问监控中心 | |

5、启动访问8080

|

image.png

2. 配置监控中心

在消费者和服务者的pom文档 加上注解

    <!--    让监控中心到注册中心找监控地址-->
    <dubbo:monitor protocol="registry"></dubbo:monitor>

4.SpringBoot配置dubbo

=====服务者=======

1. 创建工程 引入启动器以及公共接口

        <dependency>
            <groupId>com.atguigu.gmall</groupId>
            <artifactId>interface-gmall</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.0</version>
        </dependency>

2. 配置文件

#服务的名称
dubbo.application.name=user-service-provider
#注册中心地址
dubbo.registry.address=192.168.234.100:2181,192.168.234.101:2181,192.168.234.102:2181
#注册中心类型
dubbo.registry.protocol=zookeeper
#接口传输协议
dubbo.protocol.name=dubbo
#传输端口
dubbo.protocol.port=20880
#监控注册协议  registry自己去监控中心找
dubbo.monitor.protocol=registry

3.在需要暴露的接口上加Service

@Service
@org.springframework.stereotype.Service
public class UserServiceImpl implements UserService {

4. 启动类加EnableDubbo

@EnableDubbo // 开启基于注解的dubbo功能
@SpringBootApplication
public class BootUserServiceApplication {

=======消费者======

1. 创建工程 引入启动器以及公共接口

        <dependency>
            <groupId>com.atguigu.gmall</groupId>
            <artifactId>interface-gmall</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.0</version>
        </dependency>

2. 配置文件

dubbo.application.name=order-service-consumter
dubbo.registry.address=192.168.234.100:2181,192.168.234.101:2181,192.168.234.102:2181
dubbo.registry.protocol=zookeeper
dubbo.monitor.protocol=registry

3. 只需要在调用的接口上@Reference

//    @Autowired
    @Reference
    UserService userService;

4. 启动类添加Enbale 跑程序

image.pngimage.png

=====SpringBoot整合的三种方式=========

1. 导入dubbo-starter 在application.properties里配置属性,使用@Service@[暴露服务] @Refece [引用服务] @EnableDubbo[配置注解扫描]

2.删除application 保留dubbo.xml 配置文件 使用@ImportResource[导入xml配置文件]

3.使用Api

@Configuration
public class DubboConfig {

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

    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setAddress("192.168.234.100:2181,192.168.234.101:2181,192.168.234.102:2181");
        return registryConfig;
    }
    @Bean
    public ProtocolConfig protocolConfig(){
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(20882);
        return protocolConfig;
    }
    @Bean
    public ServiceConfig<UserService> serviceConfig(UserService userService){
        ServiceConfig<UserService> userServiceServiceConfig = new ServiceConfig<>();
        userServiceServiceConfig.setInterface(UserService.class);
        userServiceServiceConfig.setRef(userService);
        userServiceServiceConfig.setVersion("1.0.0");
        return userServiceServiceConfig;
    }
}

主配置类@DubboComponentSacn(配置类路径) 扫描配置类

5. Dubbo功能配置

https://dubbo.incubator.apache.org/zh/docs/v2.7/user/references/xml/

1. 启动时检查

当服务不在线时 启动不检查
image.pngimage.png
设置没有注册中心也不报错
image.png

2.超时设置

    @Reference(check = false,timeout = 2000) 单位毫秒 超过2秒没有结束服务  防止大量阻塞
    UserService userService;

配置优先级:
image.png
image.png
image.png

3.重试次数

  1. 不包含第一次 retries = 3 就是第一次失败就会重试3次 当有多台服务器会调用不同的进行尝试

    //    @Autowired
     @Reference(check = false,timeout = 2000,retries = 3)
     UserService userService;
    
  2. image.png

    4.多版本

  3. 有两个版本 分别注册到注册中心

image.png
image.png

  1. 根据版本号调用

image.png
结果:
image.png

  1. 随机调用

image.png
结果:访问3次
image.png

5.本地存根

官网的解释是这样的:在 Dubbo 中利用本地存根在客户端执行部分逻辑
远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub 1,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy
Proxy是需要通过Dubbo访问的接口

1. 设置接口存根

public class UserServiceStub implements UserService {

    private final UserService userService;

    /**
     * 传入的是UserService远程代理对象
     * @param userService
     */
    public UserServiceStub(UserService userService) {
        super();
        this.userService = userService;
    }

    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("本地被调用了");
        if (!StringUtils.isEmpty(userId)){
           return userService.getUserAddressList(userId);
        }

        return null;
    }
}

2.在接口注入添加stub = “com.atguigu.gmall.service.impl.UserServiceStub”

    @Reference(check = false,timeout = 2000,retries = 3,version = "1.0.0",stub = "com.atguigu.gmall.service.impl.UserServiceStub")

我的理解: dubbo通过stub = “com.atguigu.gmall.service.impl.UserServiceStub”找到 UserServiceStub 把userService通过构造器传入,继承userService实现方法 这时可以加入一些判断 然后return userService.getUserAddressList(userId); 这个userService是传入的service 实现功能 到了OrderServiceImpl 里注入的UserService调用的就是UserServiceStub的getUserAddressList方法(就近调用)

6. 高可用

1. zookeeper宕机和dubbo直连

zookeeper注册中心宕机 本地任然有缓存知道服务者的地址 可以继续访问
也可以dubbo直连 直接连接服务者的地址
image.png

2. 集群模式下 Dubbo的负载均衡

1.基于权重的随机负载均衡

总体概率一定 哪台服务器执行不确定
image.png

2. 基于权重的轮询的均衡机制

根据权重依次轮询 如访问到第五次 超过权重就跳过
image.png

3. 基于最少活跃数的负载均衡

总会找处理请求最快的服务器
image.png

4. 一致性hash

image.png

3. 负载均衡模拟机制

1. 设置程序多开

启动三个程序 也就是两个服务者 分别在不同端口注册
image.png
image.png

2. 启动消费者 访问测试

1. 默认情况下 随机访问的机制

11122312

2. 添加了负载均衡


//    @Autowired
    @Reference( loadbalance = "roundrobin")
    UserService userService;

控制台就变成了轮询的方式 123123

3.添加权重访问

image.png
11112233

4.服务降级

1.什么是服务降级

image.png

2. 怎么实现

  1. 返回null

image.png

  1. 容错

image.png

5. 容错模式

Failover Cluster
失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。

重试次数配置如下:
<dubbo:service retries="2" />
或
<dubbo:reference retries="2" />
或
<dubbo:reference>
    <dubbo:method name="findFoo" retries="2" />
</dubbo:reference>

Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。

Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。

集群模式配置
按照以下示例在服务提供方和消费方配置集群模式
<dubbo:service cluster="failsafe" />
或
<dubbo:reference cluster="failsafe" />

6. 整合hystrix

1. 加入启动器

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

2.在启动类上注释来启用hystrix

@SpringBootApplication
@EnableHystrix
public class ProviderApplication {

3. 配置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.");
    }
}

4.配置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";
    }

======源码分析======

1. RPC原理

image.png
image.png

2. netty通讯原理

Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。它极大地简化并简化了TCP和UDP套接字服务器等网络编程。
BIO:(Blocking IO)
image.png
NIO (Non-Blocking IO)
image.png
Netty基本原理:
boss监听准备就绪事件 组成队列给work执行 多路复用
Selector 一般称为选择器,也可以翻译为多路复用器,
Connect(连接就绪)、Accept(接受就绪)、Read(读就绪)、Write(写就绪)
image.png

3.Dubbo原理

1.dubbo框架设计

image.png
l config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
l proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy 为中心,扩展接口为 ProxyFactory
l registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory, Registry, RegistryService
l cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance
l monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService
l protocol 远程调用层:封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter
l exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
l transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec
l serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool

2.标签解析

  1. BeanDefinitionParser是Spring的标签解析器 打开继承树

image.png

  1. parse方法就是解析标签方法 debug 他是挨个解析

image.png

  1. 给他的构造器打上断点 向前一步 发现有名称空间处理

image.pngimage.png
容器启动 解析每一个标签 保存到xxxconfig Service会封装成ServiceBean reference封装为referentbean

3.服务暴露

  1. 标签解析完成后会将配置封装成ServiceBean
  2. 实现了 InitializingBean 和 ApplicationListener

image.png
InitializingBean:组件创设置完对象会调用方法
image.png
ApplicationListener:当我们IOC容器刷新完成会调用方法
image.png

  1. debug这两个方法 ServiceBean实现了这两个接口

image.png
把获取的标签保存到ServiceBean
image.png
image.png
image.pngimage.png

  1. 下一步就到了onApplicationEvent方法

如果是要暴露的 还没有暴露就调用export()方法 所以export()就是暴露方法
image.png
5.看doexport 这个是执行暴漏方法
image.png

  1. 判断检查一大堆 执行暴露地址的方法

image.png

  1. 获取协议地址和端口 继续执行

image.png

  1. 获取UserService接口和实现类的执行者对象

image.png
image.png 就是该对象他的url地址和端口
image.png

  1. 上面执行器再封装然后暴露

image.png
点进去 查看结构树
image.png
找到DubboProtocol的export方法
image.png
找到RegistryProtocol的export方法
image.png

  1. 先到 RegistryProtocol

把封装的爆露器进行暴漏
image.png
注册提供者保存服务的信息
image.png
image.png

  1. 后到DubboProtocol

打开Server 这个就会调用netty进行暴漏 直到最底层的netty
image.png
image.png

  1. 总的执行图

获取invoker执行器
用protocol暴露执行器
protocol有两个暴漏器 DubboProtocol RegistryProtocol
DubboProtocol 开启服务器
RegistryProtocol 保存暴漏服务的地址保存
image.png

4. 服务引用

  1. 扫描到配置文件reference属性的时候就会找ReferenceBean这个类

image.png

  1. ReferenceBean这个类 实现了Factory的工厂 所以等到注入的时候就调用Get方法找

image.png
image.png
image.png

  1. 进入方法 有个初始化方法

image.png

  1. 检查一大堆属性后 创建代理对象

把这些信息给代理对象 包括注册中心地址 方法名 接口 版本等
image.png
image.png

  1. 进入 这个方法

需要远程调用 urls放的是注册中心的地址 从注册中心获取接口
image.png
image.png

  1. refprotocol 有 DubboProtocol 和 RegistryProtocol
  2. 断点 DubboProtocol 到的 refer 方法 (调用中心)image.png
  3. 断点到 RegistryProtoco l的 refer 方法 (注册中心)

image.png

  1. 先到 RegistryProtoco 的refer

根据地址得到注册中心的信息
image.png
有个dorefer 传入地址 远程要引用的Service
image.png
订阅服务提供者提供的服务
image.png

  1. 订阅完就来到了DubboProtocol 的 refer 方法 执行远程引用

image.png
远程引用方法 调用谁 url的地址 最终返回执行者 核心在获取客户端
image.png
image.png

  1. 打开getClients

image.png
根据连接数创建客户端 然后初始化
image.png
进去 发现要进行连接
image.png
再进 看看连接什么 发现用Exchanger连接
image.png
使用传输器连接
image.png
继续进 最后这个连接就到netty的底层了
image.png
image.png
最后会返回一个invoke
image.png
最后回到 RegistryProtoco 这样提供者的地址 和消费者的代理 都有了image.png
到这里就完成了 这里有了代理对象
image.png
总结:

  1. ReferenceBean 获取注入的对象 调用GetObject —> 初始化init方法
  2. init—>ProxyFactory —> Protocol
  3. Procotol —> DubboProtocol 和 RegistryProtocol
  4. DubboProtocol 负责进行去和服务器连接
  5. RegistryProtocol 订阅服务 并且把invoke信息保存到注册表中
  6. 然后封装好 整个返回 invoke代理对象
  7. invoke代理对象有远程的客服端连接 也有远程服务的url地址信息

image.png

5.服务调用

  1. 给调用者发送请求

image.png

  1. UserService是一个代理对象 层层封装了invoker

image.png

  1. 进来 invoke方法 invoke本身就是层层封装 先把参数和方法封装成一个远程调用的Rpcinvoke

image.png

  1. 进来 第一个调用的就是集群容错重试的invoke

image.png

  1. 继续进 这个方法就是去注册中心找到底有几个方法可以执行

image.png
找到了2个 一个是 1.0版本 一个是2.0版本
image.png

  1. 获取负载均衡机制

image.png

  1. 继续调用 invoke 进入

根据负载均衡 选择调用的invoke 最后选中了2.0方法
image.png

  1. 现在就进入了 filter 环节 统计各个信息 层层封装invoke 最后到Dubboinvoke

最终把所有的filter解除完就会真正的执行Dubboinvoke目标方法
image.png

  1. 一步一步进入 直到Dubboinvoke

首先拿到方法信息
image.png

  1. 获取客户端 里面保存了Dubbo调用服务的地址以及要连上的服务的地址

image.png

  1. 客户端发请求 返回方法结果

image.png

  1. 进入 拿到客户端发送请求 继续进 拿到通道发送 最后来到真正发送请求的地方

模拟一个请求对象 发送请求 最后返回结果
image.png

  1. 因为设置了超时 在返回中超时了 进入了catch 进行报错 又调用invoke进行重试

image.png

  1. 重试成功 拿到了结果 返回 整个结果就拿到了

image.png
image.png