最近Dubbo又重新开始了维护,并且提供了和Spring-Boot整合的Dubbo-Starter。作为Dubbo的忠实使用者,真的是感动啊!这不,赶紧搭建个小Demo来爽了一把。
一、项目结构
我们一共搭建3个模块,common模块定义了服务提供者和服务消费者都需要使用的实体类和服务接口,provider模块定义了服务接口的具体实现,consumer模块定义了一个控制器并注入服务使用。
二、common模块
1、新建一个Spring-Boot项目(或模块),命名为dubbo-common。首先引入dubbo-starter的依赖,因为注册中心使用了ZooKeeper,所以zkclient也是需要的。
<!--dubbo-springBoot依赖-->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.11</version>
</dependency>
2、定义服务的公共接口,提供基本的增删改查功能,并定义一个返回值的封装类。
/**
* 基础接口类
* @author z_hh
* @date 2018年12月28日
*/
public interface BaseSerivce<T> {
/**
* 新增记录
* @param t
* @return
*/
public T create(T t);
/**
* 根据主键删除
* @param pk
* @return
*/
public Integer delete(Long pk);
/**
* 根据主键更新记录
* @param t
* @return
*/
public Integer update(T t);
/**
* 根据主键查询
* @param pk
* @return
*/
public T get(Long pk);
}
/**
* 结果返回类
* @author z_hh
* @date 2018年12月28日
*/
public class Results {
/**
* 成功
* @param content
* @return
*/
public static Object success(Object content) {
Map<String, Object> map = createMap();
map.put("success", true);
map.put("content", content);
return map;
}
/**
* 失败
* @param code
* @param message
* @return
*/
public static Object fail(Integer code, String message) {
Map<String, Object> map = createMap();
map.put("success", false);
map.put("code", code);
map.put("message", message);
return map;
}
private static Map<String, Object> createMap() {
return new HashMap<>();
}
}
3、定义学生实体类。
可以使用lombok简化pojo的代码。
/**
* 学生实体
* @author z_hh
* @time 2018年8月1日
*/
public class Student implements Serializable {
private static final long serialVersionUID = -6913673650612146588L;
// id
private Long id;
// 姓名
private String name;
// 性别:1男 2女
private Integer sex;
// 手机号码
private String mobile;
// 生日
private Date birthday;
// 住址
private String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", mobile=" + mobile + ", birthday=" + birthday
+ ", address=" + address + "]";
}
}
4、定义学生服务接口类。
这里我们就使用公共接口提供的功能,暂时不做扩展。
/**
* 学生服务接口类
* @author z_hh
* @time 2019年1月2日
*/
public interface StudentService extends BaseSerivce<Student> {
}
5、值得注意的是,我们将一个服务注册为Dubbo的组件时,需要在类上面使用两个注解:Dubbo的@Service和Spring的@Component(或者@Service等)。为了方便,我们可以定义一个混合注解,同时包含Service和Component的功能。
/**
* 包含com.alibaba.dubbo.config.annotation.Service
* 和org.springframework.stereotype.Component
* 的混合注解
* @author z_hh
* @time 2019年1月2日
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Service
@Component
public @interface DubboComponent {
/* org.springframework.stereotype.Component --start */
@AliasFor(annotation = Component.class)
String value() default "";
/* org.springframework.stereotype.Component --end */
/* com.alibaba.dubbo.config.annotation.Service --start */
@AliasFor(annotation = Service.class)
Class<?> interfaceClass() default void.class;
@AliasFor(annotation = Service.class)
String interfaceName() default "";
@AliasFor(annotation = Service.class)
String version() default "";
/* Service的其它属性 */
/* com.alibaba.dubbo.config.annotation.Service --end */
}
二、provider模块
1、新建一个Spring-Boot项目(或模块),命名为dubbo-provider。只需要引入common模块的依赖即可。
<!-- 基础公共模块 -->
<dependency>
<groupId>cn.zhh</groupId>
<artifactId>dubbo-common</artifactId>
<version>1.0</version>
</dependency>
2、定义StudentService的实现类。
这里我们使用Map模拟数据库,并且使用自己定义的混合注解@DubboComponent声明这是一个Dubbo的组件。
/**
* StudentService实现类
* @author z_hh
* @time 2019年1月2日
*/
@DubboComponent
public class StudentServiceImpl implements StudentService {
private HashMap<Long, Student> students = new HashMap<>();
private AtomicLong idGenerator = new AtomicLong(1);
// 初始化一条数据
{
Student initStudent = new Student();
initStudent.setId(0L);
initStudent.setName("zhh");
initStudent.setSex(1);
initStudent.setMobile("15800158000");
initStudent.setBirthday(new Date());
initStudent.setAddress("广东省广州市天河区xx街道oo巷");
students.put(initStudent.getId(), initStudent);
}
@Override
public Student create(Student t) {
t.setId(idGenerator.getAndIncrement());
students.put(t.getId(), t);
return t;
}
@Override
public Integer delete(Long pk) {
if (students.containsKey(pk)) {
students.remove(pk);
return 1;
}
return 0;
}
@Override
public Integer update(Student t) {
Long id = t.getId();
if (students.containsKey(id)) {
students.put(id, t);
return 1;
}
return 0;
}
@Override
public Student get(Long pk) {
return students.get(pk);
}
}
3、配置。
在application.properties配置以下内容:应用名、是否开启服务、注册中心地址。
## Dubbo provider config
spring.dubbo.application.name=dubbo-provider
spring.dubbo.server=true
spring.dubbo.registry.address=zookeeper://localhost:2181
三、consumer模块
1、新建一个Spring-Boot项目(或模块),命名为dubbo-consumer。除了引入common模块的依赖以外,还要引入web相关的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 基础公共模块 -->
<dependency>
<groupId>cn.zhh</groupId>
<artifactId>dubbo-common</artifactId>
<version>1.0</version>
</dependency>
2、定义一个控制器,注入服务并使用。
注意,使用@Reference注解(com.alibaba.dubbo.config.annotation.Reference)引入Dubbo的组件。
/**
* 学生控制器
* @author z_hh
* @time 2019年1月2日
*/
@RestController
@RequestMapping("/students")
public class StudentController {
@Reference
private StudentService service;
@PostMapping("/")
public Object create(@RequestBody Student student) {
Student entity = service.create(student);
return Results.success(entity);
}
@GetMapping("/{id:[\\d]}")
public Object get(@PathVariable Long id) {
Student entity = service.get(id);
return Results.success(entity);
}
@DeleteMapping("/{id:[\\d]}")
public Object delete(@PathVariable Long id) {
Integer count = service.delete(id);
if (count > 0) {
return Results.success("删除成功!");
}
return Results.fail(-1, "删除失败!");
}
}
3、配置。
在application.properties配置以下内容:http访问端口、应用名、注册中心地址。
server.port=8082
## Dubbo consumer config
spring.dubbo.application.name=dubbo-consumer
spring.dubbo.registry.address=zookeeper://localhost:2181
四、注册中心和监控中心
1、使用ZooKeeper作为注册中心:将安装包解压缩,修改配置文件,然后启动即可(依赖Java环境,具体操作可以网上找相关资料参考)。推荐一个可视化客户端:ZooViewer。
2、将dubbo-admin.war放到tomcat的webapps目录下,然后启动Tomcat即可(和ZooKeeper放在一台服务器,不同的话去网上查下是否需要修改什么东西)。
3、dubbo-admin的war包和zookeeper的安装压缩包 已上传到我的资源(点击下载)。
五、Demo测试
1、打开ZooViewer,查看ZooKeeper的目录结构,这时候除了初始数据外什么也没有。
2、打开dubbo-admin监控中心:地址ip:port/dubbo-admin,默认账号密码root/root。这时候服务提供者也是什么都没有。
3、运行dubbo-provider应用。
(1)应用启动成功。
(2)ZooKeeper上的目录结构发生了变化,多了根目录dobbo、以接口名称命名的子节点及其providers子节点。
(3) dubbo后台监控中心也可以看到多了一个服务提供者。
4、运行dubbo-consumer应用。
(1)应用启动成功。
(2)ZooKeeper上的目录结构发生了变化,接口节点下面多了consumers子节点。
(3) dubbo后台监控中心也可以看到多了一个服务消费者。
5、访问dubbo-consumer。
浏览器输入http://localhost:8082/students/0访问,可以看到以下结果:
至此,demo演示完毕了。