Dubbo的基本应用与高级应用

基础dubbo调用
提供者接口(DemoService 接口中有sayHello方法)
public interface DemoService {
String sayHello(String name);
}
提供者实现(version,版本号,用于区分 )
@Service(version = “default”)

public class DefaultDemoService implements DemoService {
@Override
public String sayHello(String name) {
System.out.println(“执行了服务” + name);
URL url = RpcContext.getContext().getUrl();
return String.format("%s:%s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问
}
}
消费者基础调用
@Reference(version = “timeout”, timeout = 3000)
private DemoService demoService;
public static void main(String[] ar6gs) throws IOException {
ConfigurableApplicationContext context = SpringApplication.run(TimeoutDubboConsumerDemo.class);
DemoService demoService = context.getBean(DemoService.class);
System.out.println((demoService.sayHello(“xxx”)));
}
dubbo在springboot配置文件中的配置
dubbo.scan.base-packages=com.tuling.provider.service
在上面单单写一个@Service肯定是没用的需要配置配置文件来使用,配置完后,dubbo将会来扫描该包,扫描到相关类,解析类和其中的注解,根据类中的注解做相关的操作。
dubbo.application.name=${spring.application.name}
需要我们定义应用
dubbo.registry.address=zookeeper://127.0.0.1:2181
定义的服务注册到zk中,作为注册中心
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
当前的提供者应用支持dubbo,dubbo默认使用netty,这里指netty的端口为20880
(dubbo支持多种协议,具体需要那种协议需要我们配置使用)

dubbo怎么表示一个服务
我们访问一个http协议的服务
http://ip:port/DemoService
如果我们通过dubbo协议
dubbo://ip:port/DemoService
协议+ip+端口+服务名+版本+组名
例子:
提供者中:
@Service(version = “default” group=“xxx”)
private DemoService demoService;
在这里协议,端口都是在配置文件中配置的,一般也不写在java类中,这个类中服务名为DemoService 。版本version 为default,组名group为xxx
提供者中指定使用某个服务;
@Service(version = “default” ,protocol = “dubbo1”)
指定使用dubbo1服务
消费者中指定版本和组:
@Reference(version = “default”, group= “xxx”)
负载均衡
如果我们在配置文件中配置多个dubbo服务;
dubbo.protocols.p1.id=dubbo1
dubbo.protocols.p1.name=dubbo
dubbo.protocols.p1.port=20881
dubbo.protocols.p1.host=0.0.0.0

dubbo.protocols.p1.id=dubbo2
dubbo.protocols.p1.name=dubbo
dubbo.protocols.p1.port=20882
dubbo.protocols.p1.host=0.0.0.0

dubbo.protocols.p1.id=dubbo3
dubbo.protocols.p1.name=dubbo
dubbo.protocols.p1.port=20884
dubbo.protocols.p1.host=0.0.0.0

这里我们配置了三个dubbo服务器
@Service(version = “default” ,loadbalance = “roundrobin”)
使用轮询
也可以在消费端配置,如果消费端和服务端都配置了,以消费端为准
@Reference(version = “generic”, loadbalance = “roundrobin”)
还有随机,一次性hash,最少活跃数;
轮询:轮流使用
随机:随机使用
一次性hash:把参数通过hash运算,去找对应的提供者,也就是说一个参数会固定找某个服务提供者
最少活跃数:在消费端计数;一开始服务端都被设置为0次;次数一样时,消费端随机发起请求到服务端,接收到请求的那个服务端,消费端会给这个服务端的最少活跃数自己做+1操作。如果得到请求的结果就-1;当服务端的最少活跃数最少时,消费端就会去找他做交互。
服务超时
消费者调用一个服务
1、消费者发送请求
2、服务端执行服务
3、服务端返回响应
服务端和消费端的服务超时

服务端配置超时时间
@Servcie(version =“timeout” timeout=6000) 6秒钟
消费端配置超时间
@Reference(version = “timeout”, timeout = 6000) 6秒钟
如果在服务端和消费端只在其一方配置了超时时间,比如我们这边配置服务端6秒,那么服务端和消费端的超时时间就都是6秒。如果单单在消费端配置了这个那么也是这种效果。
如果服务端和消费端都配置了时间,并且消费端和服务端配置的时间不一样。
比如消费端3秒,服务端6秒。
那么如果服务端的程序需要执行5秒,消费端就会抛出超时,而服务端正常运行。
集群容错
默认情况下Failover Cluster,报错去重试其他服务器,所有的提供者都会被重启一次,如果都失败了,就抛异常。
可以配置:@Reference(timeout = 1000, cluster = “failfast”)
failfast(快速失败):只调用一次,失败一次就抛异常。
failsafe(失败安全):失败直接忽略,返回空,不b会抛异常
failbcak(失败自动恢复):失败后记录下来,定时重发;
forking:并行调用多个服务器,有一个成功就返回,本次服务调用成功,可以设置并行个数。
broadcast:广播调用所有提供者,有一个报错就报错,都成功才成功。

服务降级
服务降级:
消费者的容错配置;
@Reference(version = “timeout”, timeout = 1000, mock = “fail: return 123”)
private DemoService demoService;
容错策略:如果调用demoService报错,返回123
@Reference(version = “timeout”, timeout = 1000, mock = “force: return 123”)
private DemoService demoService;
调用demoService,直接返回123不管调用是否成功。

本地存根(本地伪装)
服务提供者提供的,
@Reference(version = “timeout”, timeout = 1000, stub = “true”)
private DemoService demoService;
比如我们调用demoService的sayhello方法,这里设置了本地存根后会去类中找DemoServiceStub类,先执行这个类里面的sayhello方法,在stub的sayhello方法中还有一个sayhello方法。这里面的sayhello方法才是我们真正要执行的方法。比如我们设置Failover,每个提供者都会试一次。重试的就是里面Failover方法。

public class DemoServiceStub implements DemoService {
private final DemoService demoService;
// 构造函数传入真正的远程代理对象
public DemoServiceStub(DemoService demoService){
this.demoService = demoService;
}
@Override
public String sayHello(String name) {
// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
try {
return demoService.sayHello(name); // safe null
} catch (Exception e) {
// 你可以容错,可以做任何AOP拦截事项
return “容错数据”;
}
}
}

参数回调
消费端调用完服务端之后,消费端提供一个回调函数,服务提供端可以调用这个回调函数。
在不需要回调方法的时候
提供者端接口代码
String sayHello(String name);
提供这个方法就可以了。如果需要回调则需要再添加两个参数
// 添加回调
default String sayHello(String name, String key, DemoServiceListener listener) {
return null;
};
消费者端代码
demoService.sayHello(“xxx”, “d1”, new DemoServiceListenerImpl())
demoService.sayHello(“xxx”, “d2”, new DemoServiceListenerImpl())
demoService.sayHello(“xxx”, “d3”, new DemoServiceListenerImpl())

d1,d2,d3是真正用来区分的值,后面的对象是提供者接受到消费者的回调函数后,再利用该类,像消费端发送消息使用的。
提供者端实现代码
接收到消费者的回调后,进行处理,通过key进行判断选择,通过callback再次往提供者发送消息。

@Service(version = “callback”, methods = {@Method(name = “sayHello”, arguments = {@Argument(index = 2, callback = true)})}, callbacks = 3)
public class CallBackDemoService implements DemoService {}
在实现类CallBackDemoService类名上方做@Service(version = “callback”, methods = {@Method(name = “sayHello”, arguments = {@Argument(index = 2, callback = true)})}, callbacks = 3)配置sayhello方法的下标为2的参数是用来回调的。callbacks = 3,最大同时支持3个回调。
方法的实现:
public String sayHello(String name, String key, DemoServiceListener callback) {
System.out.println(“执行了回调服务” + name);
callback.changed(“xxxx”);
}
异步调用
之前将的都是同步调用;
在dubbo当中有很多中支持异步的调用,目前先说一种;
提供者接口代码
default CompletableFuture sayHelloAsync(String name) {
return null;
};
提供者实现类
@Service(version = “async”)
在类名之上添加 async表示异步的。
@Override
public CompletableFuture sayHelloAsync(String name) {
System.out.println(“执行了异步服务” + name);
return CompletableFuture.supplyAsync(() -> {
return sayHello(name);
});
}
sayHelloAsync会执行的很快, sayHello(name)要等到消费端真正返回(另起一个线程执行)
消费端代码
DemoService demoService = context.getBean(DemoService.class);
// 调用直接返回CompletableFuture
CompletableFuture future = demoService.sayHelloAsync(“异步调用”); // 5
future.whenComplete((v, t) -> {
if (t != null) {
t.printStackTrace();
} else {
System.out.println(“Response: " + v);
}
});
System.out.println(“结束了”);
跟提供者端一样,执行的非常快,监听背后的服务是否执行完毕,在真正拿到结果后再去执行里面的方法。
泛化调用
引入服务
@Reference(id = “demoService”, version = “default”, interfaceName = “com.tuling.DemoService”, generic = true)
private GenericService genericService;
我们引入的还是DemoService服务,
GenericService genericService = (GenericService) context.getBean(“demoService”);
Object result = genericService.$invoke(“sayHello”, new String[]{“java.lang.String”}, new Object[]{“周瑜”});
好处是不依赖服务端提供的接口,可以用来做测试使用;
泛化服务
应用于提供者端
@Service(interfaceName = “com.tuling.DemoService”, version = “generic”)
public class GenericDemoService implements GenericService {
@Override
public Object $invoke(String s, String[] strings, Object[] objects) throws GenericException {
System.out.println(“执行了generic服务”);
return “执行的方法是” + s;
}
}
服务消费者还是调用DemoService,但其实执行的是我们GenericService里面的方法,理解成做假操作,挂羊头卖狗肉。
Dubbo中的REST
提供了dubbo服务,但是消费者没有dubbo,我们就可以使用rest
rest是一个协议,需要在application.properties配置文件中去配置,
dubbo.protocol.name=rest
dubbo.protocol.port=8083
提供者代码
@Service(version = “rest”, protocol = “p2”)
@Path(“demo”)
public class RestDemoService implements DemoService {
@GET
@Path(“say”)
@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
@Override
public String sayHello(@QueryParam(“name”) String name) {
System.out.println(“执行了rest服务” + name);
URL url = RpcContext.getContext().getUrl();
return String.format(”%s: %s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问
}
}
底层是用tomcat去接收http的请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值