1.version版本控制
比如我们现在有两个服务提供者,他们分别对这个接口的实现方式不一样,那么消费者通过代理对象到底调用哪个实现呢,这就可以通过version版本控制来实现,@Reference注解的version和@Service注解的version需要配对,如下:
//服务提供者1
@Service(version = "special")
public class SiteServiceImpl implements SiteService {
@Override
public String test(String s) {
return "王佳和"+s;
}
}
//服务提供者2
@Service(version = "default")
public class SiteServiceImpl1 implements SiteService {
@Override
public String test(String s) {
return "王佳和1"+s;
}
}
//消费者
@RestController
@RequestMapping("/site")
public class SiteController {
@Reference(version = "default")
SiteService siteService;
@GetMapping("/test")
public String test(@RequestParam(value = "name") String name){
return siteService.test(name);
}
}
2.protocol协议用法
我们不一定非得用dubbo协议,可以在yml中定义多个protocal对象,每一个protocal再定义一个id,然后每一个服务提供者可以声明protocal属性,指定这个服务提供者使用的是什么协议。
dubbo:
application:
name: site-service-provider
registry:
address: zookeeper://192.168.197.200:2181
protocols:
protocol1.id: pro1
protocol1.name: dubbo
protocol1.port: 20881
protocol1.host: 0.0.0.0
protocol2.id: pro2
protocol2.name: dubbo
protocol2.port: 20882
protocol2.host: 0.0.0.0
protocol3.id: pro3
protocol3.name: dubbo
protocol3.port: 20883
protocol3.host: 0.0.0.0
# protocol:
# name: dubbo
# port: 20882.
//在暴露服务时指明要使用的协议
@Service(version = "special",protocol = "protocol1")
public class SiteServiceImpl implements SiteService {
@Override
public String test(String s) {
return "王佳和"+s;
}
如果配置了多个协议,但是@Service注解中没有设置protocol属性,那么每一个协议都会起作用,会为此服务提供者创建多个服务入口,这样的话多个服务提供者可能每一个服务都有多个入口,这些入口间端口使用不会冲突的,可以理解为每一个服务都会被分配一个ip地址,服务之间都是隔离的,意思就是192.168.145.1:20221和192.168.145.2:20221不冲突。
3.使用URL指定服务提供者
针对一个服务提供者有多个协议这种情况,消费者到底调用哪一个呢?可以使用URL来指定服务提供者。
4.服务超时
服务超时timeout可以在消费者@Reference上面配置,也可以在服务提供者@Service上面进行配置。
如果只在服务提供者上面配置超时时间的话,比如配置2秒,整体调用过程需要3秒,如果超时了,会记录错误日志,消费者方会超时报错,但是提供方依旧会向下执行,并且会重试调用两次。
如果在消费者和服务提供者上面都配置了超时时间,比如消费者配置超时时间5秒,服务提供者配置超时时间2秒,整体调用过程需要3秒,调用过程时间超过了消费者上配置的时间后,消费者方才会超时报错,服务提供者上的超时时间只做日志记录用。
@Reference(version = "version1",timeout = 5000) //消费者上配置
@Service(version = "version1",protocol = "protocol1",timeout = 2000) //服务提供者上配置
5.集群容错
-
failover(默认):当出现失败时,会进行重试,默认重试两次,并且可以使用分布式锁来解决幂等问题。
-
failfast:当出现失败时,立即报错,不进行重试。
-
failsafe:失败不报错,记入日志。
-
failback:失败就失败,开启定时任务,定时重发。
-
forking:并行访问多个服务器,获取某一个结果即视为成功。
6.服务降级MOCK的使用
消费者通过mock参数可以实现服务降级,降级分为两种:
-
mock = force:return 返回数据,表示消费方对该服务的方法调用都直接返回对应的返回数据,根本不发起远程调用,用来屏蔽不重要的服务。
-
mock=fail:return 返回数据,表示消费方对该服务的方法调用失败或超时后,再返回对应的返回数据,不抛出异常,用来容忍不重要的服务不稳定时对调用方的影响。
@Reference(version = "version1",timeout = 1000,mock = "fail:return timeout")
@Reference(version = "version2",timeout = 1000,mock = "force:return mocktest")
7.本地存根
本地存根其实也是降级的一种,就是在消费者端利用stub进行类似代理的降级。
@RestController
@RequestMapping("/stubsite")
public class StubSiteController {
@Reference(version = "version2",timeout = 1000,stub = "true")
SiteService siteService;
@GetMapping("/test")
public String test(@RequestParam(value = "name") String name){
return siteService.test(name); //实际调用的是SiteServiceStub中的test方法
}
}
//要与SiteService接口同级
public class SiteServiceStub implements SiteService {
private final SiteService siteService;
public SiteServiceStub(SiteService siteService) {
this.siteService = siteService;
}
@Override
public String test(String s) {
try {
return siteService.test(s);
}catch (Exception e){
return "stub"+s;
}
}
}
8.异步调用
是靠CompletetableFuture实现的,实现异步计算。
// api-interface
public interface SiteService {
String test(String s);
default CompletableFuture<String> testAsync(String s) {
return null;
}
}
// 服务提供者
@Service(version = "async")
public class ASyncSiteServiceImpl implements SiteService {
@Override
public String test(String s) {
return "计算的结果为:5235465";
}
@Override
public CompletableFuture<String> testAsync(String s) {
System.out.println("现在正在异步计算结果。。。");
return CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return test(s);
});
}
}
// 服务消费者
@RestController
@RequestMapping("/asyncsite")
public class AsyncSiteController {
@Reference(version = "async")
private SiteService siteService;
@GetMapping("/asynctest")
public String test(@RequestParam(value = "name") String name) throws InterruptedException {
//设置异步调用
CompletableFuture<String> future = siteService.testAsync(name);
//设置监听,回调方法,非阻塞
future.whenComplete((v, e) -> {
if(e == null){
System.out.println("返回的结果是:"+v);
}else {
e.printStackTrace();
}
});
System.out.println("可以先执行之后的事情1");
System.out.println("可以先执行之后的事情2");
System.out.println("可以先执行之后的事情3");
Thread.sleep(1000);
return "success:这是一次成功的异步调用测试";
}
}
执行结果: