1 dubbo介绍
Dubbo是一款高性能RPC框架,旨在解决分布式环境下各个服务间依赖调用问题。dubbo框架包括如下几个角色
Provider: 服务提供方。
Consumer: 服务调用方。
Registry: 服务注册与发现的注册中心。
Monitor: 统计服务的调用次调和调用时间的监控中心。
Container: 服务运行容器。
2 快速入门案例
首先引入dubbo依赖
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
2.1 生产者代码编写
2.1.1 yml配置文件
dubbo:
application:
name: dubbo-provider # dubbo应用名称
registry:
address: 127.0.0.1:2181 # zk地址
protocol: zookeeper # zk协议
protocol:
name: dubbo # 默认dubbo协议
port: 20880 # dubbo协议暴露端口
monitor:
protocol: registry # 添加monitor监控
server:
port: 7001
2.1.2 启动程序配置
在启动主程序添加@EnableDubbo注解即可
2.1.3 编写service
接口:
public interface ProviderService {
String hello(String name);
}
package com.provider.service;
import com.alibaba.dubbo.config.annotation.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author huwenlong
* @date 2020/4/12 12:11
*/
@Slf4j
@Component
@Service
public class ProviderServiceImpl implements ProviderService {
@Override
public String hello(String name) {
log.info("hello method start, name:{}", name);
return "hello:" + name;
}
}
注意,这里引入的Service注解是dubbo包中的
2.2 消费者代码编写
2.2.1 yml配置文件
dubbo:
application:
name: dubbo-consumer
registry:
address: zookeeper://127.0.0.1:2181
monitor:
protocol: registry
2.1.2 启动程序配置
在启动主程序添加@EnableDubbo注解即可
2.1.3 引入ProviderService
生产环境中会把ProviderService打到jar包里,这里学习的时候笔者直接把ProviderService接口拷贝到消费服务相同的路径下
package com.provider.service;
/**
* @author huwenlong
* @date 2020/4/12 12:10
*/
public interface ProviderService {
String hello(String name);
}
2.1.4 测试代码
@Reference
private ProviderService providerService;
@Test
public void helloTest() {
System.out.println(providerService.hello("小明"));
}
注意,这里的Reference注解是dubbo下的
输出:
hello:小明
回头我们看服务提供方控制台,也有日志打印。
3 常用配置
3.1 取消启动检查
dubbo消费者启动的时候默认是检查服务提供方存不存在的,如果不存在则报错,这里只需要在配置文件中取消检查就行了
dubbo-error.png
单个service配置:@Reference(check = false) 优先
全局配置
dubbo:
consumer:
check: false # 取消启动检查
这样消费者服务就能正常启动
3.2 消费者超时时间和重试次数设置
dubbo服务调用方调用服务的时候默认超时时间是1秒
生产者接口和实现类中添加timeout方法
@Override
public String timeout() {
log.info("timeout method execute");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "timeout";
}
消费者调用报错
消费者
生产者
这里我们看到超时之后又重试了两次
重试次数配置
由于各种原因调用服务超时,可以进行重试机制(默认2次,加上本次调用,总共访问生产者3次)
单个service配置:@Reference(retries = 0) 优先
全局配置:
dubbo
consumer:
retries: 0 # 重试次数配置
消费者
生产者
可以看到只调用了一次
通常在幂等(方法不管执行多少次影响都不变,查询、删除、修改)方法设置重试,提高程序健壮性
在非幂等(方法执行次数不同会有不同的影响,如添加)方法设置重试次数为0
超时时间配置:
单个service配置:@Reference(timeout = 2000) 优先
全局配置:
dubbo
consumer:
timeout: 3000 # 超时时间设置
再次调用则没问题
3.3 多版本配置
系统升级的时候可以配置服务提供者版本信息
服务提供者我们把原来的service定义成1.0.0版本,再加一个2.0.0版本的service
@Service(version = "1.0.0")
public class ProviderServiceImpl implements ProviderService {
2.0.0版本的service
@Component
@Service(version = "2.0.0")
public class ProviderServiceImpl2 implements ProviderService {
@Override
public String hello(String name) {
return "hello2:" + name;
}
@Override
public String timeout() {
System.out.println("timeout2 method execute");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "timeout";
}
}
调用方调用的时候可以指定服务版本
@Reference(version = "1.0.0")
private ProviderService providerService;
@Reference(version = "2.0.0")
private ProviderService providerService2;
@Test
public void versionTest() {
System.out.println(providerService.hello("小明"));
System.out.println(providerService2.hello("小明"));
}
输出:
hello:小明
hello2:小明
3.4 本地代理
dubbo消费者可以配置本地代理,利用代理做一些额外操作,如检查、容错等
1 创建实现类实现服务方接口方法
2 在实现类中设置构造函数,传入服务接口代理对象
3 调用方配置代理类,@Reference(stub = "com.provider.service.ProviderServiceProxy")
这样在使用服务的时候会先走代理类中的逻辑创建ProviderServiceProxy代理类
public class ProviderServiceProxy implements ProviderService {
private ProviderService providerService;
public ProviderServiceProxy(ProviderService providerService) {
this.providerService = providerService;
}
@Override
public String hello(String name) {
if (StringUtils.isEmpty(name)) {
return "invalid param";
}else {
return providerService.hello(name);
}
}
@Override
public String timeout() {
return null;
}
}
@Reference注解添加stub属性
@Reference(version = "1.0.0", stub = "com.provider.service.ProviderServiceProxy")
private ProviderService providerService;
测试代码
@Test
public void stubTest() {
System.out.println(providerService.hello("小明"));
System.out.println(providerService.hello(null));
}
输出:
hello:小明
invalid param
3.5 dubbo直连
如果zk宕机,可以通过dubbo直连来直接调用服务
@Reference(version = "1.0.0", url = "127.0.0.1:20880")
private ProviderService providerService3;
测试代码
@Test
public void directInvokeTest() {
System.out.println(providerService3.hello("小明"));
}
可以正确输出