本文将创建3个工程:
dubbo-provider 服务提供者工程
dubbo-consumer 服务消费者工程
dubbo-api 服务接口
1 api 方式使用
1.1 注册中心方式
创建dubbo-api工程,提供者和消费者均需要依赖
提供一个接口
public interface HelloService {
/**
* 返回一句话
* @param name
* @return: java.lang.String
* @Author: jt-ape
* @Date: 2021/2/1 12:32
*/
public String sayHello(String name);
}
创建dubbo-provider工程
提供一个实现
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "dubbo say hello:"+ name;
}
}
创建测试类,使用api方式暴露服务,注册中心使用zookeeper
public class DubboProviderApiTest {
@Test
public void test() throws IOException {
// 创建应用
ApplicationConfig applicationConfig = new ApplicationConfig("provider");
// 创建协议
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("dubbo");
// port 设置为-1表示随机端口
protocolConfig.setPort(20880);
// 创建注册中心
RegistryConfig registryConfig = new RegistryConfig();
// zookeeper集群
registryConfig.setAddress("121.36.168.192:2181,121.36.168.192:2182,121.36.168.192:2183");
registryConfig.setProtocol("zookeeper");
// 注册服务
ServiceConfig<HelloService> serviceServiceConfig = new ServiceConfig<>();
serviceServiceConfig.setApplication(applicationConfig);
serviceServiceConfig.setProtocol(protocolConfig);
serviceServiceConfig.setRegistry(registryConfig);
serviceServiceConfig.setInterface(HelloService.class);
serviceServiceConfig.setRef(new HelloServiceImpl());
// 暴露服务
serviceServiceConfig.export();
System.in.read();
}
pom.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>dubbo-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>dubbo-provider</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建consumer工程
创建测试类,使用api方式调用服务
public class DubboConsumerApiTest {
@Test
public void test() {
// 创建应用
ApplicationConfig applicationConfig = new ApplicationConfig("consumer");
// 创建注册中心
RegistryConfig registryConfig = new RegistryConfig();
// zookeeper集群
registryConfig.setAddress("121.36.168.192:2181,121.36.168.192:2182,121.36.168.192:2183");
registryConfig.setProtocol("zookeeper");
ReferenceConfig<HelloService> referenceConfig = new ReferenceConfig<>();
referenceConfig.setApplication(applicationConfig);
referenceConfig.setRegistry(registryConfig);
referenceConfig.setInterface(HelloService.class);
HelloService helloService = referenceConfig.get();
System.out.println(helloService.sayHello("dubbo api"));
}
}
1.2 使用广播的方式
修改注册中心地址
固定写法:multicast://224.
1.3 使用随机端口
将协议的端口设置为-1,则会随机使用一个端口.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>dubbo-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>dubbo-consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>dubbo-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2 与springboot 整合使用
同样使用上面创建的三个工程,从上面的pom.xml中可以看出创建的是springboot工程。
2.1 dubbo-provider工程配置
application.yml
dubbo:
application:
name: dubbo-application-provider
registry:
address: 121.36.168.192:2181,121.36.168.192:2182,121.36.168.192:2183
protocol: zookeeper
scan:
base-packages: com.example.dubboprovider.service.impl
protocol:
name: dubbo
port: 20880
HelloServiceImpl 加上dubbo的@Service注解注册服务
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "dubbo say hello:"+ name;
}
}
启动类:
@SpringBootApplication
public class DubboProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DubboProviderApplication.class, args);
}
}
2.2 dubbo-consumer配置
application.yml
dubbo:
application:
name: dubbo-application-consumer
registry:
address: 121.36.168.192:2181,121.36.168.192:2182,121.36.168.192:2183
protocol: zookeeper
启动类使用@Reference订阅服务:
@SpringBootApplication
public class DubboConsumerApplication implements InitializingBean {
@Reference
private HelloService helloService;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(helloService.sayHello("hhahhahh"));
}
public static void main(String[] args) {
SpringApplication.run(DubboConsumerApplication.class, args);
}
}
4 高级应用
4.1 负载均衡
dubbo默认的负载均衡策略是随机取一个服务。
首先配置多个协议,相当于注册多个服务,修改提供者配置,增加一个dubbo协议端口为20881,现在注册了两个服务,20880、20881
修改dubbo-provider工程
多协议配置
application.yml
dubbo:
application:
name: dubbo-application-provider
registry:
address: 121.36.168.192:2181,121.36.168.192:2182,121.36.168.192:2183
protocol: zookeeper
scan:
base-packages: com.example.dubboprovider.service.impl
protocol:
name: dubbo
port: 20880
protocols:
# key1为任意协议的唯一键
key1:
id: dubbo1
# 同样也配置dubbo协议,使用不同的端口
name: dubbo
port: 20881
修改服务实现类HelloServiceImpl,将端口号打印出来
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
int port =RpcContext.getContext().getUrl().getPort();
return "["+ port + "]" + "dubbo say hello:"+ name;
}
}
修改dubbo-consumer工程
修改启动类DubboConsumerApplication
@SpringBootApplication
public class DubboConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DubboConsumerApplication.class, args);
}
}
修改pom.xml文件,增加web包starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
新增controller
@RestController
public class HelloController {
@Reference
private HelloService helloService;
@RequestMapping("/say")
public String say() {
String result = helloService.sayHello("hahahaha");
System.out.println(result);
return result;
}
}
启动dubbo-provider、dubbo-consumer
浏览器访问:http://localhost:8080/say
可以看到会随机选一个服务。
4.1.1 四种负载均衡策略
random 随机
roundrobin 轮询
leastactive 最少活跃数,是在消费端统计的,每个服务都有一个属性active,选出一个服务,就会对其active属性+1,服务返回就对active属性-1,如果有相同的最小活跃数,则随机。
consistenthash 一致性hash,根据传入的参数不同,匹配到一个服务
4.1.2 负载均衡配置
修改服务实现类,@Service注解添加loadbalance属性,配置为轮询
@Service(loadbalance = "roundrobin")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
int port =RpcContext.getContext().getUrl().getPort();
return "["+ port + "]" + "dubbo say hello:"+ name;
}
}
可以看出结果为轮询获取服务。
4.1.3 优先级别
负载均衡的配置可以配置在服务端,也可配置在消费端,其中消费端的优先级比服务端高。
修改dubbo-consumer工程
修改HelloController,在@Reference注解加入loadbalance属性
@RestController
public class HelloController {
@Reference(loadbalance = "random")
private HelloService helloService;
@RequestMapping("/say")
public String say() {
String result = helloService.sayHello("hahahaha");
System.out.println(result);
return result;
}
}
可以看到结果又变为随机获取服务。
4.2 服务超时
服务端超时时间既可以在服务端配置,也可以在消费端配置,但是二者表示的含义是不一样的,且造成的结果也是不一样的。
一方配置超时时间
指仅在消费者或提供者一方单独配置,只在一方配置超时时候,消费端如果超出时间还未收到返回结果,则会抛出异常,服务端在执行服务时,会检查服务执行时间,如果超时,会打印一个错误日志,服务会正常执行完成。
两方同时配置超时时间
消费者和提供者同时配置超时时间
4.2.1 一方配置
修改dubbo-provider工程
修改服务实现类,@Service加上timeout属性,并且在sayHello方法中睡3s
@Service(loadbalance = "roundrobin",timeout = 2000)
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
}
修改pom.xml在引入的dubbo包下排除log4j,否则日志不会打印。
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.3</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
日志配置,在resources下增加log4j.properties文件
log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n
分别启动doubble-provider、dubbo-consumer,浏览器访问http://localhost:8080/say
消费端结果如下:
提供者结果如下:
可以看出服务依然执行完成,会打印timeout日志
4.3.2 两方配置
现在在以上代码基础上,修改服务实现类,将timeout修改未7000ms
@Service(loadbalance = "roundrobin",timeout = 7000)
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
}
修改dubbo-consumer在HelloController的@Reference上配置timeout为4000ms
@RestController
public class HelloController {
@Reference(loadbalance = "random",timeout = 4000)
private HelloService helloService;
@RequestMapping("/say")
public String say() {
String result = helloService.sayHello("hahahaha");
System.out.println(result);
return result;
}
}
分别启动doubble-provider、dubbo-consumer,浏览器访问http://localhost:8080/say
消费端结果如下:
提供者结果如下:
可以看到服务消费端超时报错,服务提供端一切正常。
4.3 集群容错
集群容错就是集群调用失败时,Dubbo提供的一种后续处理方案。可在消费端或服务端配置,如果同时配置将会使容错失效。
dubbo提供了6种种容错方案:
failover Cluster :失败自动切换,出现失败后会重新调用其它服务器,一般用于读操作,但是重试会带来更长延迟。可通过 retries=“2” 来设置重试次数(不含第一次)。这种方式是dubbo的默认配置
failfast Cluster:快速失败,即失败后就报错,一般用于新增等操作。
failsafe Cluster:失败安全,指失败后忽略,一般用于写日志等
failback Cluster:失败自动恢复,指后台记录失败的请求,定时重发,一般用于消息发送。
forking Cluster:并行调用多个服务,一个成功即返回,一般用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。
broadcast Cluster:广播调用所有提供者,依次调用,有一个报错了就报错,一般用于通知所有提供者更新缓存或日志等本地资源信息。
4.3.1 示例应用
4.3.1.1 默认容错方案
通过章节4.2.2可以看出dubbo默认的容错方案失败自动切换,重试了两次,加上第一次调用所以共调用了三次,所以输出了3次字符串。
4.3.1.2 配置容错方案
本示例配置一个forking Cluster 并行调用,其它方案可自行测试。
修改dubbo-provider工程
修改application.yml,注释掉20881的端口
dubbo:
application:
name: dubbo-application-provider
registry:
address: 121.36.168.192:2181,121.36.168.192:2182,121.36.168.192:2183
protocol: zookeeper
scan:
base-packages: com.example.dubboprovider.service.impl
protocol:
name: dubbo
port: 20880
# protocols:
# key1:
# id: dubbo1
# name: dubbo
# port: 20881
修改服务实现类HelloServiceImpl,@Service注解新增属性cluster,并修改睡眠时间,也可注释,以免浪费时间。
@Service(loadbalance = "roundrobin",timeout = 7000, cluster = "forking")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
}
启动dubbo-provider 工程,本次启动后只注册了一个服务。
然后再修改dubbo-provider工程的服务实现类HelloServiceImpl,将实现方法上抛出异常,然后再次启动,注意不要停掉上面已经启动的应用。注意需要在idea启动配置上勾选上运行多个实例启动,配置如下:
修改HelloServiceImpl
@Service(loadbalance = "roundrobin",timeout = 7000, cluster = "forking")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
throw new RuntimeException("测试集群容错。。。");
// return "["+ port + "]" + "dubbo say hello:"+ name;
}
}
修改application.properties,修改端口为20881
dubbo:
application:
name: dubbo-application-provider
registry:
address: 121.36.168.192:2181,121.36.168.192:2182,121.36.168.192:2183
protocol: zookeeper
scan:
base-packages: com.example.dubboprovider.service.impl
protocol:
name: dubbo
port: 20881
# protocols:
# key1:
# id: dubbo1
# name: dubbo
# port: 20881
idea配置多个实例运行
启动两个实例后即注册了两个服务。
下一步启动dubbo-consumer工程,访问http://localhost:8080/say
查看20880后台,返回成功
查看20881后台,返回失败
查看客户端后台,返回成功
4.3.2 自定义容错方案
自定义容错方法需要实现org.apache.dubbo.rpc.cluster.Cluster接口
修改dubbo-api工程
创建MyCluster.java,自定义容错逻辑为,如果选取的服务异常,那么再重复调用这个服务五次,如果还是异常则返回错误消息
public class MyCluster implements Cluster {
@Override
public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
return new AbstractClusterInvoker<T>(directory) {
@Override
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadBalance) throws RpcException {
List<Invoker<T>> copyInvokers = invokers;
// 检查服务列表
this.checkInvokers(invokers, invocation);
List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size());
Result result = null;
// 通过负载均衡策略选择一个服务
Invoker<T> invoker = this.select(loadBalance, invocation, copyInvokers, invoked);
// 自定义容错方案,
for (int i=0;i<5;i++) {
result = invoker.invoke(invocation);
if (result.hasException()) {
result = new AsyncRpcResult(invocation);
result.setValue(invoker.getUrl().getPort()+":大哥我尽力了,尝试了五次都失败了");
}
}
return result;
}
};
}
}
配置MyCluster
resources目录下面新建META-INF/dubbo/org.apache.dubbo.rpc.cluster.Cluster配置文件,内容如下,其中mycluster为自定义容错策略的名称。
mycluster=com.example.dubboapi.service.cluster.MyCluster
项目结果如下:
修改dubbo-provider
applicaton.yml,将协议的端口号配置为-1,启动多个实例会分配一个端口从20880依次+1。
dubbo:
application:
name: dubbo-application-provider
registry:
address: 121.36.168.192:2181,121.36.168.192:2182,121.36.168.192:2183
protocol: zookeeper
scan:
base-packages: com.example.dubboprovider.service.impl
protocol:
name: dubbo
port: -1
# protocols:
# key1:
# id: dubbo1
# name: dubbo
# port: 20881
修改实现类HelloServiceImpl ,配置cluster的值为mycluster自定义容错策略。
@Service(loadbalance = "roundrobin",timeout = 7000, cluster = "mycluster")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
throw new RuntimeException("测试集群容错。。。");
// return "["+ port + "]" + "dubbo say hello:"+ name;
}
}
现在启动3个提供者,再启动消费者,浏览器访问http://localhost:8080/say
可以看到返回了我们自定义的错误消息,且只有20882的提供者有被调用。自定义容错策略成功。
4.4 服务降级
通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。
mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
还可以改为 mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
且配置只能再消费端,配置再服务端,服务启动会报错。并且返回信息如果是中文会导致mock失效。
修改dubbo-provider 工程
修改服务实现类HelloServiceImpl ,去掉@Service注解的cluste属性r
@Service(loadbalance = "roundrobin",timeout = 7000)
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
throw new RuntimeException("测试集群容错。。。");
// return "["+ port + "]" + "dubbo say hello:"+ name;
}
}
修改dubbo-consumer工程
修改HelloController,给@Reference 添加mock属性配置。
@RestController
public class HelloController {
@Reference(loadbalance = "roundrobin",timeout = 4000,mock = "force: return hhh")
private HelloService helloService;
@RequestMapping("/say")
public String say() {
String result = helloService.sayHello("hahahaha");
System.out.println(result);
return result;
}
}
修改pom文件,使用mock会依赖fastjson包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
启动服务端和消费端,浏览器访问http://localhost:8080/say
通过提供方的控制台可以看出此时根本未调用服务。
4.5 本地存根
在客户端执行部分逻辑,这段逻辑一般由服务提供者提供。
本地存根实现:
1.需要配置stub属性,可配置再服务端,可配置再消费端,以消费端为准。
提供端配置如下
Service(stub = "com.example.dubboapi.service.HelloServiceStub")
或
Service(stub = "true")
如果stub的值未true,那么包名必须和服务接口一致,类名必须是接口名+Stub。
2.需要提供stub实现
Stub 类必须要提供传入代理对象的构造函数。 必须实现代理对象的接口。
修改dubbo-api
提供stub实现
public class HelloServiceStub implements HelloService{
private HelloService helloService;
public HelloServiceStub(HelloService helloService) {
this.helloService = helloService;
}
@Override
public String sayHello(String name){
System.out.println("提供者调用服务之前执行....");
return helloService.sayHello(name);
}
}
修改dubbo-provider
修改接口实现类HelloServiceImpl ,@Service添加stub属性
@Service(loadbalance = "roundrobin",timeout = 7000,stub = "com.example.dubboapi.service.HelloServiceStub")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
// throw new RuntimeException("测试集群容错。。。");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
}
启动服务端、消费端,浏览器访问http://localhost:8080/say
可以看到消费端的控制台打印了加入的逻辑,所以这段逻辑是运行再客户端。
4.6 本地伪装
本地伪装和服务降级是一样的都是,服务提供方全部挂掉后,注意是服务挂掉,就是说如果方法抛出的是业务异常如RuntimeException,那么不会走mock的逻辑,必须是服务级别的异常比如挂掉、超时,与业务方法抛出的异常无关,客户端不抛出异常,而是通过 Mock 数据返回。下面介绍几种mock用法
4.6.1 使用简介
// 如果mock的值是true,那么需要在服务接口包下面提供一个名为“接口名+Mock” 的实现。
@Reference(mock = "true")
public class HelloServiceMock implements HelloService{
@Override
public String sayHello(String name) {
return "额 我是一个伪装者";
}
}
// mock 也可指定一个伪装类。
@Reference(mock = "com.example.dubboapi.service.HelloServiceMock")
// mock 也可指定一个伪装类。
@Reference(mock = "com.example.dubboapi.service.HelloServiceMock")
return使用:使用 return 来返回一个字符串表示的对象,作为 Mock 的返回值。
empty: 代表空,基本类型的默认值,或者集合类的空值
null: null
true: true
false: false
JSON 格式: 反序列化 JSON 所得到的对象
//
@Reference(mock = "return {name:\"我是一个小mock\",age:\"20\"}")
throw使用:
使用 throw 来返回一个 Exception 对象,作为 Mock 的返回值。
// 抛出RPCException
@Reference(mock = "throw")
// 抛出指定异常
@Reference(mock = "throw java.lang.RuntimeException")
fail本文4.4已经演示,这里再次强调下:
fail失败返回,接口调用失败了会返回,会发起远程调用,这里的失败不是业务级别的异常,比如你服务方法里抛出的RuntimeException并不会走mock,而是服务级别的异常,比如挂掉,超时。
force本文4.4已经演示,这里再次强调下:
force强制返回,不在意服务端怎么样,强制走mock逻辑。
这里增加一点也与 throw连用
// 强制抛出指定异常
@Reference(mock = "force:throw java.lang.RuntimeException")
4.6.2 演示return json
修改dubbo-api工程
新增User.java
public class User implements Serializable {
private String name;
private String age;
public User(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
修改接口HelloService,新增一个方法
public interface HelloService {
/**
* 返回一句话
* @param name
* @return: java.lang.String
* @Author: jt-ape
* @Date: 2021/2/1 12:32
*/
public String sayHello(String name);
public User sayHello();
}
修改dubbo-provider工程
修改实现类HelloServiceImpl,实现新增的方法,注意实现方法抛出的是RpcException
@Service(loadbalance = "roundrobin",timeout = 7000)
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
// throw new RuntimeException("测试集群容错。。。");
throw new RpcException("我看看这个异常");
// return "["+ port + "]" + "dubbo say hello:"+ name;
}
@Override
public User sayHello() {
System.out.println("22222222222222222222");
// return new User("jack", "12");
throw new RpcException("一定要抛RpcException,或者将服务挂掉");
}
}
修改dubbo-consumer
修改HelloController ,新增一个方法,并在@Reference注解中添加mock属性
@RestController
public class HelloController {
@Reference(loadbalance = "roundrobin",timeout = 4000,mock = "return {name:\"我是一个小mock\",age:\"11111\"}")
private HelloService helloService;
@RequestMapping("/say")
public String say() {
String result = helloService.sayHello("hahahaha");
System.out.println(result);
return result;
}
@RequestMapping("/user")
public String say1() {
User result = helloService.sayHello();
System.out.println(result);
return result.getName();
}
}
启动dubbo-provider,dubbo-consumer,启动成功后再关掉dubbo-provider浏览器访问:http://localhost:8080/user
4.7 参数回调
从服务器端调用客户端逻辑,只需要声明服务方法中哪个参数是 callback 类型即可。
修改dubbo-api工程
新增一个回调接口CallBackListener
public interface CallBackListener {
public String callBack();
}
修改接口HelloService,重载一个sayHello参数为CallBackListener
public interface HelloService {
/**
* 返回一句话
* @param name
* @return: java.lang.String
* @Author: jt-ape
* @Date: 2021/2/1 12:32
*/
public String sayHello(String name);
public User sayHello();
public String sayHello(CallBackListener callBackListener);
}
修改dubbo-provider工程
修改服务实现类,实现接口新增的方法,@Service注解增加methods和callbacks属性,
以下注解表示,methods属性的配置表示sayHello方法下标为0的参数是回调参数,callbacks表示回调实例最多有3个。
@Service(loadbalance = "roundrobin",timeout = 7000, methods = {
@Method(name = "sayHello",arguments = {
@Argument(index = 0, callback = true)})},callbacks = 3)
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
// throw new RuntimeException("测试集群容错。。。");
// throw new RpcException("我看看这个异常");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
@Override
public User sayHello() {
System.out.println("22222222222222222222");
// return new User("jack", "12");
throw new RpcException("我看看这个异常一定要抛出这个异常RemotingException");
}
@Override
public String sayHello(CallBackListener callBackListener) {
return callBackListener.callBack();
}
}
修改dubbo-consumer工程
修改HelloController,新增一个方法say2
@RestController
public class HelloController {
@Reference(loadbalance = "roundrobin",timeout = 4000,mock = "fail: return 111")
private HelloService helloService;
@RequestMapping("/say")
public String say() {
String result = helloService.sayHello("hahahaha");
System.out.println(result);
return result;
}
@RequestMapping("/user")
public String say1() {
User result = helloService.sayHello();
System.out.println(result);
return result.getName();
}
@RequestMapping("/callback")
public String say2() {
return helloService.sayHello(new CallBackListener() {
@Override
public String callBack() {
return "通过回调方法返回客户端的东西";
}
});
}
}
启动dubbo-provider,启动dubbo-consumer,浏览器访问http://localhost:8080/callback,这里遇到一个非常坑的问题,我dubbo版本是用的2.7.3,结果这个版本使用注解添加methods 属性会报错,xml方式没有试过,后将dubbo版本改为了2.7.5,然后正常了
修改dubbo-provider,dubbo-consumer工程的dubbo版本,将dubbo和dubbo-spring-boot-starter的版本都要改成2.7.5
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.5</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
然后启动访问浏览器返回正常。
4.8 异步调用
Dubbo 的异步调用时使用 CompletableFuture 为基础, 通过NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。
4.8.1 RpcContest
修改dubbo-provider 工程
修改接口实现类上,将@Servcie上的method属性去掉。
@Service(loadbalance = "roundrobin",timeout = 7000)
public class HelloServiceImpl implements HelloService {
private final Map<String, CallBackListener> listeners = new ConcurrentHashMap<String, CallBackListener>();
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
// throw new RuntimeException("测试集群容错。。。");
// throw new RpcException("我看看这个异常");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
@Override
public User sayHello() {
System.out.println("22222222222222222222");
// return new User("jack", "12");
throw new RpcException("我看看这个异常一定要抛出这个异常RemotingException");
}
@Override
public String sayHello(CallBackListener callBackListener) {
return callBackListener.callBack();
}
}
修改dubbo-consumer工程
修改HelloController,使用RpcContext.getContext().asyncCall() 来调用服务,asyncCall方法有两个实现,其中传入Runable接口表示不关心返回,这时是没有返回值的,传入Callable时候会返回CompletableFuture。
@RestController
public class HelloController {
@Reference
private HelloService helloService;
@RequestMapping("/say")
public String say() {
CompletableFuture<String> completableFuture = RpcContext.getContext().asyncCall(() -> {
return helloService.sayHello("异步调用");
});
String result = helloService.sayHello("hahahaha");
System.out.println(result);
try {
String s = completableFuture.get();
System.out.println("异步返回结果:"+s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return result;
}
@RequestMapping("/user")
public String say1() {
User result = helloService.sayHello();
System.out.println(result);
return result.getName();
}
@RequestMapping("/callback")
public String say2() {
return helloService.sayHello(new CallBackListener() {
@Override
public String callBack() {
return "通过回调方法返回客户端的东西";
}
});
}
}
启动服务,访问http://localhost:8080/say
可以看到异步调用没有阻塞,先输出了同步调用结果。
4.8.2 RpcContext + @Method
修改dubbo-consumer工程
修改HelloController,给@Reference注解加上methods属性,配置如下:
其中,@Method还有属性return 如果等于fasle则不会生成CompletableFuture对象,这里不做演示。
@RestController
public class HelloController {
@Reference(methods = {
@Method(name = "sayHello",async = true)})
private HelloService helloService;
@RequestMapping("/say")
public String say() {
String result = helloService.sayHello("hahahaha");
System.out.println(result);
return result;
}
@RequestMapping("/user")
public String say1() {
User result = helloService.sayHello();
System.out.println(result);
return result.getName();
}
@RequestMapping("/callback")
public String say2() {
return helloService.sayHello(new CallBackListener() {
@Override
public String callBack() {
return "通过回调方法返回客户端的东西";
}
});
}
}
这时sayHello方法已经时异步方法了,直接调用会返回null,比如我们现在直接启动服务端和消费端,访问http://localhost:8080/say
我们可以通过使用RpcContext来接收异步返回结果
修改dubbo-consumer工程
修改HelloController,修改第一个say方法,使用RpcContext来获取一个CompletableFuture,通过它的get()方法获取返回结果,get()会阻塞。
@RestController
public class HelloController {
@Reference(methods = {
@Method(name = "sayHello",async = true)})
private HelloService helloService;
@RequestMapping("/say")
public String say() {
String result = helloService.sayHello("hahahaha");
System.out.println(result);
CompletableFuture<String> completableFuture = RpcContext.getContext().getCompletableFuture();
try {
String s = completableFuture.get();
System.out.println("异步返回结果:"+s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return result;
}
@RequestMapping("/user")
public String say1() {
User result = helloService.sayHello();
System.out.println(result);
return result.getName();
}
@RequestMapping("/callback")
public String say2() {
return helloService.sayHello(new CallBackListener() {
@Override
public String callBack() {
return "通过回调方法返回客户端的东西";
}
});
}
}
启动服务,浏览器访问http://localhost:8080/say
4.8.3 CompletableFuture
可以直接修改方法签名,返回CompletableFuture,则可以不使用RpcContext。
修改dubbo-api工程
修改接口HelloService,新增一个asyncCall方法
public interface HelloService {
/**
* 返回一句话
* @param name
* @return: java.lang.String
* @Author: jt-ape
* @Date: 2021/2/1 12:32
*/
public String sayHello(String name);
public User sayHello();
public String sayHello(CallBackListener callBackListener);
public CompletableFuture<String> asyncCall();
}
修改dubbo-provider工程
修改服务实现类,HelloServiceImpl,实现接口方法,注意这里方法里的逻辑需要放到CompletableFuture里执行。
@Service(loadbalance = "roundrobin",timeout = 7000)
public class HelloServiceImpl implements HelloService {
private final Map<String, CallBackListener> listeners = new ConcurrentHashMap<String, CallBackListener>();
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
// throw new RuntimeException("测试集群容错。。。");
// throw new RpcException("我看看这个异常");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
@Override
public User sayHello() {
System.out.println("22222222222222222222");
// return new User("jack", "12");
throw new RpcException("我看看这个异常一定要抛出这个异常RemotingException");
}
@Override
public String sayHello(CallBackListener callBackListener) {
return callBackListener.callBack();
}
@Override
public CompletableFuture<String> asyncCall() {
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "我是一个异步方法";
});
}
}
修改dubbo-consumer工程
修改HelloController,去掉@Rerence中的methods属性,新增一个方法say3
@RestController
public class HelloController {
@Reference
private HelloService helloService;
@RequestMapping("/say")
public String say() {
CompletableFuture<String> completableFuture = RpcContext.getContext().asyncCall(() -> {
return helloService.sayHello("异步调用");
});
String result = helloService.sayHello("hahahaha");
System.out.println(result);
try {
String s = completableFuture.get();
System.out.println("异步返回结果:"+s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return result;
}
@RequestMapping("/user")
public String say1() {
User result = helloService.sayHello();
System.out.println(result);
return result.getName();
}
@RequestMapping("/callback")
public String say2() {
return helloService.sayHello(new CallBackListener() {
@Override
public String callBack() {
return "通过回调方法返回客户端的东西";
}
});
}
@RequestMapping("/sync")
public String say3() throws ExecutionException, InterruptedException {
CompletableFuture<String> stringCompletableFuture = helloService.asyncCall();
return stringCompletableFuture.get();
}
}
启动服务,访问http://localhost:8080/sync
4.8.4 CompletableFuture 不阻塞获取结果的方式
修改dubbo-consumer 工程
修改HelloController,给CompletableFuture对象添加回调
@RestController
public class HelloController {
@Reference
private HelloService helloService;
@RequestMapping("/say")
public String say() {
CompletableFuture<String> completableFuture = RpcContext.getContext().asyncCall(() -> {
return helloService.sayHello("异步调用");
});
String result = helloService.sayHello("hahahaha");
System.out.println(result);
try {
String s = completableFuture.get();
System.out.println("异步返回结果:"+s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return result;
}
@RequestMapping("/user")
public String say1() {
User result = helloService.sayHello();
System.out.println(result);
return result.getName();
}
@RequestMapping("/callback")
public String say2() {
return helloService.sayHello(new CallBackListener() {
@Override
public String callBack() {
return "通过回调方法返回客户端的东西";
}
});
}
@RequestMapping("/sync")
public String say3() throws ExecutionException, InterruptedException {
CompletableFuture<String> stringCompletableFuture = helloService.asyncCall();
// 添加回调
stringCompletableFuture.whenComplete((result, exception) -> {
if (exception == null) {
System.out.println("异步返回结果:"+result);
}
});
System.out.println("输出一段话,打印再异步返回结果前面");
return "success";
}
}
启动服务,访问http://localhost:8080/sync
4.9 泛化调用
泛化调用可以不依赖服务端提供的接口,直接使用GenericService完成接口调用。
修改dubbo-api工程
修改接口HelloService,新增一个方法GenericCall。
public interface HelloService {
/**
* 返回一句话
* @param name
* @return: java.lang.String
* @Author: jt-ape
* @Date: 2021/2/1 12:32
*/
public String sayHello(String name);
public User sayHello();
public String sayHello(CallBackListener callBackListener);
public CompletableFuture<String> asyncCall();
public String genericCall(User user);
}
修改dubbo-provide 工程
修改服务实现类HelloServiceImpl,实现接口新增的genericCall方法
@Service(loadbalance = "roundrobin",timeout = 7000)
public class HelloServiceImpl implements HelloService {
private final Map<String, CallBackListener> listeners = new ConcurrentHashMap<String, CallBackListener>();
@Override
public String sayHello(String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
// throw new RuntimeException("测试集群容错。。。");
// throw new RpcException("我看看这个异常");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
@Override
public User sayHello() {
System.out.println("22222222222222222222");
// return new User("jack", "12");
throw new RpcException("我看看这个异常一定要抛出这个异常RemotingException");
}
@Override
public String sayHello(CallBackListener callBackListener) {
return callBackListener.callBack();
}
@Override
public CompletableFuture<String> asyncCall() {
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "我是一个异步方法";
});
}
@Override
public String GenericCall(User user) {
System.out.println(user);
return "泛化返回成,接收到的用户名:"+user.getName();
}
}
修改dubbo-consumer工程
修改HelloController,使用@Reference注入一个GenericService ,新增一个方法say4,注意调用方法的参数如果是POJO,可用map传递参数。
@RestController
public class HelloController {
@Reference(interfaceName = "com.example.dubboapi.service.HelloService",generic = true)
private GenericService genericService;
@Reference
private HelloService helloService;
@RequestMapping("/say")
public String say() {
CompletableFuture<String> completableFuture = RpcContext.getContext().asyncCall(() -> {
return helloService.sayHello("异步调用");
});
String result = helloService.sayHello("hahahaha");
System.out.println(result);
try {
String s = completableFuture.get();
System.out.println("异步返回结果:"+s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return result;
}
@RequestMapping("/user")
public String say1() {
User result = helloService.sayHello();
System.out.println(result);
return result.getName();
}
@RequestMapping("/callback")
public String say2() {
return helloService.sayHello(new CallBackListener() {
@Override
public String callBack() {
return "通过回调方法返回客户端的东西";
}
});
}
@RequestMapping("/sync")
public String say3() throws ExecutionException, InterruptedException {
CompletableFuture<String> stringCompletableFuture = helloService.asyncCall();
// 添加回调
stringCompletableFuture.whenComplete((result, exception) -> {
if (exception == null) {
System.out.println("异步返回结果:"+result);
}
});
System.out.println("输出一段话,打印再异步返回结果前面");
return "success";
}
@RequestMapping("/generic")
public String say4() {
Map<String,Object> user = new HashMap<String,Object>();
user.put("class", "com.example.dubboapi.model.User");
user.put("name","泛化用户");
user.put("age", "23");
return genericService.$invoke("genericCall", new String[] {
"com.example.dubboapi.model.User"}, new Object[]{
user}).toString();
}
}
启动服务,浏览器访问http://localhost:8080/generic
4.10 泛化服务
通过实现 GenericService 接口处理所有服务请求。
修改dubbo-provider工程
新增一个GenericService的实现GenericServiceImpl
@Service(interfaceName = "com.example.dubboapi.service.HelloService",version = "generic")
public class GenericServiceImpl implements GenericService {
@Override
public Object $invoke(String s, String[] strings, Object[] objects) throws GenericException {
return "这是一个泛化服务啊哈哈哈";
}
}
修改dubbo-consumer工程
修改HelloController,将之前的引入服务都注释,只保留
@RestController
public class HelloController {
@Reference(version = "generic")
private HelloService genericHelloService;
@RequestMapping("/genericService")
public String say5() {
return genericHelloService.sayHello("11111");
}
}
启动服务端和消费端,浏览器访问http://localhost:8080/say
4.11 rest调用
修改dubbo-provider工程
修改pom.xml,新增4个依赖
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.19.Final</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-http</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
修改application.yml,配置rest协议
dubbo:
application:
name: dubbo-application-provider
registry:
address: 121.36.168.192:2181,121.36.168.192:2182,121.36.168.192:2183
protocol: zookeeper
scan:
base-packages: com.example.dubboprovider.service.impl
protocol:
name: rest
port: 8083
修改HelloServiceImpl ,类上增加@Path注解配置路径,在sayHello方法添加@Get注解表示get请求,@Path配置路径,@Consumers配置传入数据格式,@Produces 指定返回数据格式,
@PathParam 指定访问路径上的参数。
@Service(loadbalance = "roundrobin",timeout = 7000)
@Path("hello")
public class HelloServiceImpl implements HelloService {
private final Map<String, CallBackListener> listeners = new ConcurrentHashMap<String, CallBackListener>();
@GET
@Path("sayHello/{name}")
@Consumes({
}) // 指定传入数据格式
@Produces({
"application/json; charset=UTF-8", "text/xml; charset=UTF-8"}) // 指定返回数据格式
@Override
public String sayHello(@PathParam("name") String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
// throw new RuntimeException("测试集群容错。。。");
// throw new RpcException("我看看这个异常");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
@Override
public User sayHello() {
System.out.println("22222222222222222222");
// return new User("jack", "12");
throw new RpcException("我看看这个异常一定要抛出这个异常RemotingException");
}
@Override
public String sayHello(CallBackListener callBackListener) {
return callBackListener.callBack();
}
@Override
public CompletableFuture<String> asyncCall() {
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "我是一个异步方法";
});
}
@Override
public String genericCall(User user) {
System.out.println(user);
return "泛化返回成,接收到的用户名:"+user.getName();
}
}
修改GenericServiceImpl ,注释调@Service注解,因为配置了rest协议,如果不注释会使用rest协议,但是GenericServiceImpl 上没有rest协议的配置。
//@Service(interfaceName = "com.example.dubboapi.service.HelloService",version = "generic")
public class GenericServiceImpl implements GenericService {
@Override
public Object $invoke(String s, String[] strings, Object[] objects) throws GenericException {
return "这是一个泛化服务啊哈哈哈";
}
}
启动dubbo-provider,浏览器访问http://localhost:8083/hello/sayHello/hahah
@QueryParam 指定url中的参数
修改dubbo-provider
修改HelloServiceImpl,在sayHello的参数上使用@QueryParam注解
@Service(loadbalance = "roundrobin",timeout = 7000)
@Path("hello")
public class HelloServiceImpl implements HelloService {
private final Map<String, CallBackListener> listeners = new ConcurrentHashMap<String, CallBackListener>();
@GET
@Path("sayHello")
@Consumes({
}) // 指定传入数据格式
@Produces({
"application/json; charset=UTF-8", "text/xml; charset=UTF-8"}) // 指定返回数据格式
@Override
public String sayHello(@QueryParam("name") String name) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int port =RpcContext.getContext().getUrl().getPort();
System.out.println("11111111111111111111111111111111111");
// throw new RuntimeException("测试集群容错。。。");
// throw new RpcException("我看看这个异常");
return "["+ port + "]" + "dubbo say hello:"+ name;
}
@Override
public User sayHello() {
System.out.println("22222222222222222222");
// return new User("jack", "12");
throw new RpcException("我看看这个异常一定要抛出这个异常RemotingException");
}
@Override
public String sayHello(CallBackListener callBackListener) {
return callBackListener.callBack();
}
@Override
public CompletableFuture<String> asyncCall() {
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "我是一个异步方法";
});
}
@Override
public String genericCall(User user) {
System.out.println(user);
return "泛化返回成,接收到的用户名:"+user.getName();
}
}
启动dubbo-provider,浏览器访问http://localhost:8083/hello/sayHello?name=123123