之前已经快速搭建了 Dubbo 入门 Demo,本篇博客将继续在此 Demo 的基础上,介绍一下 Dubbo 在实际项目开发中必然会用到的一些简单实用的技术点,只需要编写很少的代码或者进行一些注解配置即可实现,大大提高了开发效率。在本篇博客的最后,会提供源代码的下载,需要注意的是:在运行本 Demo 代码时,必须先启动 Zookeeper 作为注册中心。
一、对象序列化
我们在编写服务接口时,如果接口参数或者接口返回值,需要使用实体类对象的话,那么实体类必须要实现 Serializable 接口,否则在运行过程中会报错。既然实体类是在接口定义中使用,因此 Dubbo 服务端和客户端都必须使用,所以本 Demo 就将实体类也放到了 dubbo_interface 这个公共模块中,如下图所示:
在 dubbo_interface 公共模块中,增加了 com.jobs.domain 包,增加实体类 User
package com.jobs.domain;
import java.io.Serializable;
//实体类承载数据,要想在 Dubbo 客户端和服务端之间传输,
//必须实现 Serializable 接口
public class User implements Serializable {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
在 TestService 接口中定义一个方法使用 User 实体类:
package com.jobs.service;
import com.jobs.domain.User;
public interface TestService {
User GetUserDetail(int id);
}
在 Dubbo 服务端实现该接口:
package com.jobs.service.impl;
import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Service;
//需要注意:这里的 @Service 注解是 Dubbo 提供的
//不要使用 Spring 提供的 @Service 注解
@Service
public class TestServiceImpl implements TestService {
@Override
public User GetUserDetail(int id) {
User user;
if (id == 1) {
user = new User("任肥肥", 38);
} else {
user = new User("候胖胖", 40);
}
return user;
}
}
在 Dubbo 客户端进行调用和测试:
package com.jobs.controller;
import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/test")
public class TestController {
//这里生成远程接口代理,从而可以调用远程服务接口
@Reference
private TestService testService;
//测试实现了 Serializable 接口的实体类承载数据进行传输
//采用 restful 风格,把传递的参数写在路径上
@GetMapping("/getuser/{id}")
public User GetCal(@PathVariable("id") int uid) {
User user = testService.GetUserDetail(uid);
return user;
}
}
二、地址缓存
当 Dubbo 客户端调用过一次 Dubbo 服务端的接口之后,服务端接口的地址就被缓存到 Dubbo 客户端了,所以 Dubbo 客户端并不是每次调用服务端接口,都得向 Zookeeper 注册中心获取接口服务地址。
当接口服务地址发生变化时,Zookeeper 注册中心会通知 Dubbo 客户端,此时 Dubbo 客户端会重新到注册中心获取最新的接口地址,然后缓存到 Dubbo 客户端中。因此如果 Zookeeper 注册中心宕机挂掉了,不会影响 Dubbo 客户端调用之前已经调用过的接口服务,但是新的接口服务就无法调用了。
三、超时和重试
我们既可以在 Dubbo 客户端的 @Reference 注解上配置超时和重试,也可以在 Dubbo 服务端的 @Service 注解上配置超时和重试。但是比较推荐的做法是在 Dubbo 服务端进行配置超时和重试,因为服务的开发者知道具体接口的执行耗费时间。需要注意的是:如果同时在客户端和服务端都配置了超时和重试的话,客户端上的配置会覆盖服务端的配置。
如果不进行配置的话,超时的时间默认为 1000 毫秒,重试的次数默认为 2 次,下面列出服务端的配置:
package com.jobs.service.impl;
import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Service;
//需要注意:这里的 @Service 注解是 Dubbo 提供的
//不要使用 Spring 提供的 @Service 注解
//一般情况下,超时和重试,配置在 Dubbo 服务端,
//如果在 Dubbo 客户端配置超时和重试的话,会覆盖服务端的配置
//以下表明超时时间为 2 秒,先尝试请求 1 次,如果超时则再重试 1 次,一共最多请求 2 次
//如果不配置的话,默认超时是 1 秒钟,默认重试次数是 2 次
@Service(timeout = 2000, retries = 1)
public class TestServiceImpl implements TestService {
@Override
public User GetUserDetail(int id) {
User user;
if (id == 1) {
user = new User("任肥肥", 38);
} else {
user = new User("候胖胖", 40);
}
return user;
}
}
需要注意的是:根据业务重要性的实际情况,建议在服务端中,把读服务和写服务,进行分离。因为对于读取数据的服务,在超时后进行重试,一般情况下对业务不会有影响。但是对于写数据的接口服务来说,如果超时后进行重试,可能会影响业务,因此一般对于写服务,配置重试的次数为 0。当然要解决重复写数据对业务影响的问题,也是解决方案的,以上建议仅供参考。
四、多版本控制
对于 Java 来说,同一个接口的实现类,可以有多个。因此对于 Dubbo 服务端来说,同一个服务的实现类可以有多个,可以给不同的实现类通过 @Service 注解配置版本号,版本号是字符串,可以随意配置。在 Dubbo 客户端只需要在 @Reference 注解上配置要调用接口服务的版本,即可调用具体版本的服务接口。如下图所示,我们新建了一个 TestServiceImpl2 类实现 TestService 接口,作为一个新版本的服务。
下面列出两个版本服务的代码:
package com.jobs.service.impl;
import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Service;
//需要注意:这里的 @Service 注解是 Dubbo 提供的
//不要使用 Spring 提供的 @Service 注解
@Service(timeout = 2000, retries = 1, version = "1.0")
public class TestServiceImpl implements TestService {
@Override
public User GetUserDetail(int id) {
User user;
if (id == 1) {
user = new User("任肥肥", 38);
} else {
user = new User("候胖胖", 40);
}
return user;
}
}
package com.jobs.service.impl;
import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Service;
//这里编写了另外一个版本的服务,多个版本的服务可以同时存在
@Service(timeout = 2000, retries = 1, version = "2.0")
public class TestServiceImpl2 implements TestService {
@Override
public User GetUserDetail(int id) {
User user;
if (id == 1) {
user = new User("李墩墩", 38);
} else {
user = new User("乔豆豆", 40);
}
return user;
}
}
在 Dubbo 客户端通过 @Reference 注解上配置要调用接口服务的版本:
package com.jobs.controller;
import com.jobs.domain.User;
import com.jobs.service.TestService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/test")
public class TestController {
//这里生成远程接口代理,从而可以调用远程服务接口
//通过 version 配置,可以指定调用哪个版本的接口服务
@Reference(version = "2.0")
private TestService testService;
//测试实现了 Serializable 接口的实体类承载数据进行传输
//采用 restful 风格,把传递的参数写在路径上
@GetMapping("/getuser/{id}")
public User GetCal(@PathVariable("id") int uid) {
User user = testService.GetUserDetail(uid);
return user;
}
}
多版本控制的情况,比较适合灰度发布。接口在大规模更新之前,大部分用户仍然使用原来的接口服务,先让一部分用户使用新接口服务,如果用了一段时间没有问题的话,就可以让所有的用户都使用新接口服务,从而完成灰度发布。
本篇博客源代码下载地址:https://files.cnblogs.com/files/blogs/699532/DubboDemo2.zip
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/191130.html