Dubbo使用及原理简介

一:RPC

RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。

   

RPC两个核心模块:通讯,序列化,这两个模块决定RPC的性能好坏。

二:Dubbo

Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。官网:http://dubbo.apache.org/

  • 服务提供者Provider:暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
  • 服务消费者Consumer: 调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 注册中心Registry:注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
  • 监控中心Monitor:服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

调用关系说明:

  • 服务容器负责启动,加载,运行服务提供者。
  • 服务提供者在启动时,向注册中心注册自己提供的服务。
  • 服务消费者在启动时,向注册中心订阅自己所需的服务。
  • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  • 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

三:初体验

1.搭建注册中心

  • 进入 zookeeper-3.4.6 目录,创建 data 文件夹:mkdir data
  • 进入conf目录 ,把 zoo_sample.cfg拷贝一份并改名为 zoo.cfg
  • 打开zoo.cfg ,  修改 data 属性:dataDir=自己目录/zookeeper-3.4.6/data
  • 启动zookeeper服务:./zkServer.sh start|stop|status,输出一下表示启动成功

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

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

  • 打包dubbo-admin:mvn clean package -Dmaven.test.skip=true
  • 运行dubbo-admin:java -jar dubbo-admin-0.0.1-SNAPSHOT.jar,使用root/root登录

3.创建服务

需求:某个电商系统,订单服务需要调用用户服务获取某个用户的所有地址;我们现在 需要创建两个服务模块进行测试 

测试预期结果:订单服务web模块在A服务器,用户服务模块在B服务器,A可以远程调用B的功能。

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

粒度:服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo 暂未提供分布式事务支持。服务接口建议以业务场景为单位划分,并对相近业务做抽象,防止接口数量爆炸。不建议使用过于抽象的通用接口,如:Map query(Map),这样的接口没有明确语义,会给后期维护带来不便。

创建gmail-interface模块

创建UserAddress类:

public class UserAddress implements Serializable{
    private Integer id;//id
    private String userAddress;//收货地址
    private String userId;//用户id
    private String consignee;//收货人
    private String phoneNum;//收货号码
    private String isDefault;//是否为默认地址  Y是  N否
    //get  set
}

添加UserService服务:

public interface UserService {
	
	public List<UserAddress> getUserAddressList(String userId);

}

添加OrderService服务:

public interface OrderService {
	public void initOrder(String userId);
}

创建user-service-prodiver模块:在pom文件中依赖gmail-interface

<dependencies>
  	<dependency>
  		<groupId>com.peng.test</groupId>
  		<artifactId>gmail-interface</artifactId>
  		<version>0.0.1-SNAPSHOT</version>
  	</dependency>
  </dependencies>

添加UserServiceImpl实现类:

public class UserServiceImpl implements UserService{

	@Override
	public List<UserAddress> getUserAddressList(String userId) {
		System.out.println("UserServiceImpl.....old...");
		UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
		UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
		return Arrays.asList(address1,address2);
	}

}

创建订单服务order-service-consumer,依赖gmail-interface

创建OrderServiceImpl实现:

public class OrderServiceImpl implements OrderService {

	UserService userService;
	
	@Override
	public void initOrder(String userId) {
		//查询用户的收货地址
		List<UserAddress> userAddressList = userService.getUserAddressList(userId);
		System.out.println(userAddressList);
		
	}
}

4.集成dubbo

在user-service-prodiver中添加dubbo及zookeeper依赖

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>dubbo</artifactId>
	<version>2.6.2</version>
</dependency>
<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-framework</artifactId>
	<version>2.12.0</version>
</dependency>

配置dubbo,创建prodiver.xml文件

<?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://dubbo.apache.org/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-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
 
 	<!-- 设置包扫描 -->
	<context:component-scan base-package="com.peng.test.service.impl" ></context:component-scan>
 	
    <!--当前应用的名字  -->
	<dubbo:application name="user-service-prodiver"></dubbo:application>
	<!--指定注册中心的地址  -->
    <dubbo:registry address="zookeeper://192.168.25.128:2181" />
    <!--使用dubbo协议,将服务暴露在20880端口  -->
    <dubbo:protocol name="dubbo" port="20880" />
    <!-- 指定需要暴露的服务 -->
    <dubbo:service interface="com.peng.test.service.UserService" ref="userServiceImpl" />
</beans>

在UserServiceImpl上加@Service注解(spring的)

添加测试:

public class Test {
	
	public static void main(String[] args) {
		ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:prodiver.xml");
		classPathXmlApplicationContext.start();
		try {
			System.in.read();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

在order-service-consumer中添加dubbo及zookeeper依赖

配置dubbo,创建consumer.xml文件

<?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://dubbo.apache.org/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-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
	
	<!-- 设置包扫描 -->
	<context:component-scan base-package="com.peng.test.serice.impl" ></context:component-scan>
	
	<!-- 应用名 -->
	<dubbo:application name="order-service-consumer"></dubbo:application>
	<!-- 指定注册中心地址 -->
	<dubbo:registry address="zookeeper://192.168.25.128:2181" />
	<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
	<dubbo:reference id="userService" interface="com.peng.test.service.UserService"></dubbo:reference>
 
</beans>

在OrderServiceImpl上加@Service注解(spring)及userService上加@Autowired注解(spring)

添加测试:

public class Test {
	
	public static void main(String[] args) {
		ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("consumer.xml");
		OrderService bean = classPathXmlApplicationContext.getBean(OrderService.class);
		bean.initOrder("12");
		classPathXmlApplicationContext.start();
		try {
			System.in.read();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

先启动user-service-prodiver的测试类,在启动的测试类,会发现order-service-consumer调用了user-service-prodiver提供的服务

四:监控中心安装

  • 使用mvn package将dubbo-monitor-simple打包
  • 在target目录下会生成dubbo-monitor-simple-2.0.0.jar及dubbo-monitor-simple-2.0.0-assembly.tar.gz文件,将dubbo-monitor-simple-2.0.0-assembly.tar.gz解压,修改conf/dubbo.properties文件,将dubbo.registry.address=zookeeper://192.168.25.128:2181
  • 启动监控中心:在assembly.bin文件下,点击start.bat,浏览器访问http://localhost:8080/

  • 在prodiver.xml及consumer.xml中添加如下配置,重新启动两个测试类
<!-- 监控中心协议,如果为protocol="registry",表示从注册中心发现监控中心地址,否则直连监控中心 -->
	<dubbo:monitor protocol="registry"></dubbo:monitor>

五:整合SpringBoot

1.搭建项目

修改gmail-interface中OrderService接口

使用Eclipse的STS插件创建boot-user-service-provider,jar包

加入依赖:

<dependency>
	<groupId>com.peng.test</groupId>
	<artifactId>gmail-interface</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

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

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>dubbo</artifactId>
	<version>2.6.5</version>
</dependency>

<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-framework</artifactId>
	<version>2.12.0</version>
</dependency>

创建UserServiceImpl实现:

@Service//dubbo注解
public class UserServiceImpl implements UserService {
	@Override
	public List<UserAddress> getUserAddressList(String userId) {
		System.out.println("UserServiceImpl.....old...");
		UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
		UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
		return Arrays.asList(address1,address2);
	}
}

配置文件:

dubbo.application.name=boot-user-service-provider
dubbo.registry.address=192.168.25.128:2181
dubbo.registry.protocol=zookeeper
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.monitor.protocol=registry

启动类上添加@EnableDubbo,开启对Dubbo的支持

创建boot-order-service-consumer项目,war包

添加依赖:

<dependency>
	<groupId>com.peng.test</groupId>
	<artifactId>gmail-interface</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

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

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>dubbo</artifactId>
	<version>2.6.5</version>
</dependency>

<dependency>
	<groupId>org.apache.curator</groupId>
	<artifactId>curator-framework</artifactId>
	<version>2.12.0</version>
</dependency>

创建OrderServiceImpl实现:

@Service
public class OrderServiceImpl implements OrderService {

	@Reference//dubbo注解
	private UserService userService;
	
	@Override
	public List<UserAddress> initOrder(String userId) {
		//查询用户的收货地址
		List<UserAddress> userAddressList = userService.getUserAddressList(userId);
		return userAddressList;
	}
}

创建controller:

@Controller
public class OrderController {
	
	@Autowired
	private OrderService orderService;
	
	@RequestMapping("/initOrder")
	@ResponseBody
	public List<UserAddress> initOrder(String userId){
		List<UserAddress> initOrder = orderService.initOrder(userId);
		return initOrder;
	}

}

配置文件:

server.port=8090

dubbo.application.name=boot-order-service-consumer
dubbo.registry.address=zookeeper://192.168.25.128:2181
dubbo.monitor.protocol=registry

启动类上添加@EnableDubbo,开启对Dubbo的支持

2.测试

启动boot-user-service-provider及boot-order-service-consumer,访问http://localhost:8090/initOrder?userId=444,可以正常返回

3.SpringBoot使用原生xml配置dubbo

表写xml配置文件与之前一样,在启动类上配置@ImportResource("classpath:dubbo.xml"),取消@EnableDubbo注解

4.使用java配置dubbo

@Configuration
public class MyDubboConfig {
	
	@Bean
	private ApplicationConfig applicationConfig() {
		ApplicationConfig applicationConfig = new ApplicationConfig();
		applicationConfig.setName("boot-user-service-provider");
		return applicationConfig;
	}
	
	@Bean
	public RegistryConfig registryConfig() {
		RegistryConfig registryConfig = new RegistryConfig();
		registryConfig.setAddress("127.0.0.1:2181");
		registryConfig.setProtocol("zookeeper");
		return registryConfig;
	}
	
	@Bean
	public ProtocolConfig protocolConfig() {
		ProtocolConfig protocolConfig = new ProtocolConfig();
		protocolConfig.setName("dubbo");
		protocolConfig.setPort(20882);
		return protocolConfig();
	}
	
	@Bean
	public MonitorConfig monitorConfig() {
		MonitorConfig monitorConfig = new MonitorConfig();
		monitorConfig.setProtocol("registry");
		return monitorConfig;
	}
	
	@Bean
	public ServiceConfig<UserService> userServiceConfig(UserServiceImpl userServiceImpl){
		ServiceConfig<UserService> serviceConfig = new ServiceConfig<UserService>();
		serviceConfig.setInterface(UserService.class);
		serviceConfig.setRef(userServiceImpl);
		serviceConfig.setTimeout(3000);
		serviceConfig.setVersion("1.0.0");
		
		MethodConfig methodConfig = new MethodConfig();
		methodConfig.setName("getUserAddressList");
		methodConfig.setTimeout(1000);
		
		serviceConfig.setMethods(Arrays.asList(methodConfig));
		return serviceConfig;
	}

}

启动类上配置@EnableDubbo(scanBasePackages= {"com.peng.test.service.configuration"}),其他注解一样使用

六:配置简介

1.配置启动时检查:检查消费的服务是否在注册中心中,不在则报错

2.超时&配置覆盖关系

优先级:

  • 方法级优先,接口级次之,全局配置再次之。
  • 如果级别一样,则消费方优先,提供方次之。

3.重试次数:第一次请求失败后,会重试,第一次请求次数不算

幂等(多次请求结果一样比如:查询,删除,修改)方法适合设置重试次数,非幂等(多次请求结果不一样如:新增)方法不适合设置重试次数

4.多版本配置:程序升级后,只对部分服务器升级测试,其他依旧使用原有程序

服务提供方配置多个服务提供,通过版本号区别

服务消费方通过版本号指定消费哪个服务

5.本地存根:可以验证提交参数

编写服务实现:

public class UserServiceStub implements UserService {
	
	private final UserService userService;
	
	//必须提供有参构造器
	public UserServiceStub(UserService userService) {
		this.userService = userService;
	}


	@Override
	public List<UserAddress> getUserAddressList(String userId) {
		if (!StringUtils.isEmpty(userId)) {//验证参数
			return userService.getUserAddressList(userId);
		}
		return null;
	}

}

dubbo会通过有参构造将真是的服务传过来

6.更多配置参考dubbo开发手册:http://dubbo.apache.org/zh-cn/docs/user/quick-start.html

七:服务的高可用

1.Zookeeper宕机与Dubbo直连

将Zookepper宕机后,发现服务依旧可以调用,那是因为dubbo存在服务提供者的本地缓存,还可以通@Reference(url="127.0.0.1:20880")配置dubbo直连。

2.dubbo的负载均衡

负载均衡策略:

  • Random LoadBalance:随机,按权重设置随机概率。在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
  • RoundRobin LoadBalance:轮循,按公约后的权重设置轮循比率。存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在第二台上。
  • LeastActive LoadBalance:最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
  • ConsistentHash LoadBalance:一致性 Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。算法参见:http://en.wikipedia.org/wiki/Consistent_hashing缺省只对第一个参数 Hash,如果要修改,请配置 <dubbo:parameter key="hash.arguments" value="0,1" />缺省用 160 份虚拟节点,如果要修改,请配置 <dubbo:parameter key="hash.nodes" value="320" /

默认使用随机,使用@Reference(loadbalance="roundrobin")配置轮训的方式,可以使用dubbo的监控平台调节服务的权重

3.服务降级

当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。

服务还未调用时直接返回为空:

在消费者层面通过屏蔽达到在服务消费方调用服务时直接返回为空

服务调用失败后在返回为空:

依旧是在服务消费方,当服务消费方调用服务后返回失败,在返回为空

4.服务容错&Hystrix

集群容错模式:

  • Failover Cluster:失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次),默认。
  • Failfast Cluster:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
  • Failsafe Cluster:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
  • Failback Cluster失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
  • Forking Cluster:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
  • Broadcast Cluster广播调用所有提供者,逐个调用,任意一台报错则报错 。通常用于通知所有提供者更新缓存或日志等本地资源信息。

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

整合hystrix:

服务提供方及服务消费方加入hystrix依赖

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

服务提供方及服务消费方在启动类上加@EnableHystrix注解

服务提供方的服务方法上加@HystrixCommand注解

服务消费方的消费方法上加@HystrixCommand(fallbackMethod="hello")注解,当服务提供方出现异常,会调用hello方法

八:RPC原理

1.RPC原理

一次完整的RPC调用流程(同步调用,异步另说)如下:

  • 服务消费方(client)调用以本地调用方式调用服务;
  • client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
  • client stub找到服务地址,并将消息发送到服务端;
  • server stub收到消息后进行解码;
  • server stub根据解码结果调用本地的服务;
  • 本地服务执行并将结果返回给server stub;
  • server stub将返回结果打包成消息并发送至消费方;
  • client stub接收到消息,并进行解码;
  • 服务消费方得到最终结果。

RPC框架的目标就是要2~8这些步骤都封装起来,这些细节对用户来说是透明的,不可见的。

九:dubbo原理

1.dubbo框架设计结构

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

2.配置文件解析

dubbo的配置文件中,所有的配置都是以dubbo开头的,在spring中解析配置文件的标签都是使用BeanDefinitionParser接口的实现类来解析的,所以解析dubbo的配置标签也不例外。

dubbo实现了一个自己的标签解析器,实现了其中的parse()方法,parse(0方法是用来一条一条解析dubbo标签的,在方法的参数中传入一个beanClass,然后在方法中依次判断是否是对应类型的对象

那么这些对象有时在何时生成的呢?其实是在调用DubboBeanDefinitionParser的构造方法前调用了DubboNamespaceHandler的初始化方法,创建很多DubboBeanDefinitionParser来解析对应的标签

经过DubboBeanDefinitionParser的解析后,会将每一条标签数据放到对应的XXXConfig中,不过值得注意的是service及reference是保存在对应的Bean中的。

3.服务暴露流程

上面说过在解析标签时会创建一个ServiceBean,那么现在就来看看ServiceBean,会发现ServiceBean实现InitializingBeanApplicationListener<ContextRefreshedEvent>两个接口,InitializingBean会在创建对象时调用其afterPropertiesSet方法,ApplicationListener监听ContextRefreshedEvent,说明当IOC容器刷新完毕后会调用onApplicationEvent方法,下面就看看这两个方法。

对于afterPropertiesSet就是将之前读取到的配置信息以XXXConfig添加到serviceBean对象中。

onApplicationEvent中通过export暴露服务,经过一系列的数据验证后,来到com.alibaba.dubbo.config.ServiceConfig.doExportUrls()方法,暴露服务

循环配置的所有的dubbo协议,暴露服务,配置文件中可以配置多个<dubbo:protocol name="dubbo" port="20880" />

通过代理工厂将向外提供服务的接口及暴露的地址包装为Invoker,最后调用protocol的export方法,将Invoker传入进去,暴露服务

对于Protocol有两个重要的实现类DubboProtocol用于dubbo协议暴露服务,RegistryProtocol用于注册中心,最先来到RegistryProtocol的export()方法

来到doLocalExport()方法中

invokerDelegete中保存了暴露的接口,接口实现类,暴露的地址的信息,再次放行,又来到DubboProtocol的export方法中

首先获取暴露到zookeeper中服务的地址,之后调用openServer()

第一次需要调用createServer创建服务器

openServer()执行完毕后,netty服务器就创建完毕,之后又在RegistryProtocol的export方法中注册提供者

又在底层缓存一个暴露的url对应的服务执行器,当消费者通过url调用服务时,提供者就可以通过这个映射关系获取到服务执行器,执行服务。到这里服务就暴露出去了,dubbo底层启动netty服务,监听20880端口,当有请求进来时,netty就会根据请求的信息通过providerInvokers中缓存的信息调用对应的服务。

4.服务引用流程

对于服务的引用于服务的暴露前面步骤类似,标签<dubbo:reference/>也对应一个ReferenceBean

发现ReferenceBean是FactoryBean的实现,那么当通过在项目中需要服务的实现时就会调用ReferenceBean的getObject()方法获取服务的实现

在init()方法中,创建服务的代理对象

传入一个map,包装了注册中心地址,调用的方法,调用的接口

从注册中心中获取远程接口,refprotocol又是Protocol,对应的又是DubboProtocol及RegistryProtocol两个实现,放行后,首先来到RegistryProtocol的refer方法

在doRefer方法中

放行后又来到DubboProtocol的refer方法中

通过服务地址,在getClients()中获取客户端

通过initClient初始化客户端

 最后还是调用netty传输器连接,创建Netty客户端,服务点阅完毕后就会获取一个invoker

invoker中封装了服务地址等信息

最后又将服务的地址及服务执行器对应起来,最后将invoker返回

至此,代理对象就创建完毕

5.服务调用流程

上面服务的代理对象已经创建完毕,下面就看看,代理对象是如何执行服务的,通过代理对象执行方法时,首先来到

invoker里面层层封装着不同的invoker

最后调用doInvoke()方法 

通过负载均衡策略从Invoker的List中选择一个Invoker

一直不断地f5进入invoker()方法,最终来到DubboInvoker的doInvoke()方法

通过在服务引用中获取到的客户端发起请求,返回响应结果,invoker调用链主要用来进行数据统计等其他一些操作。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值