1. 项目工程架构
根据 dubbo《服务化最佳实践》
1、分包
建议将服务接口,服务模型,服务异常等均放在 API 包中,因为服务模型及异常也是 API 的一部分,同时,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。
如果需要,也可以考虑在 API 包中放置一份 spring 的引用配置,这样使用方,只需在 spring 加载过程中引用此配置即可,配置建议放在模块的包目录下,以免冲突,如:com/alibaba/china/xxx/dubbo-reference.xml。
2、粒度
服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo 暂未提供分布式事务支持。
服务接口建议以业务场景为单位划分,并对相近业务做抽象,防止接口数量爆炸。
不建议使用过于抽象的通用接口,如:Map query(Map),这样的接口没有明确语义,会给后期维护带来不便。
2. 新建Maven聚合工程
使用eclipse新建maven父工程,然后新建子工程,工程目录如下:
项目模块说明:
1.1 dubbo-app项目
项目的父工程,Maven项目,整合springboot2,负责管理各子模块及其依赖版本,其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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gmall</groupId>
<artifactId>dubbo-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- 继承说明:这里继承SpringBoot提供的父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath />
</parent>
<!-- 编码UTF-8,jdk版本1.8 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<modules>
<module>gmall-user</module>
<module>gmall-interface</module>
<module>gmall-web</module>
<module>gmall-user-v2</module>
</modules>
<!-- 版本说明:这里统一管理依赖的版本号 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.gmall</groupId>
<artifactId>gmall-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.gmall</groupId>
<artifactId>gmall-user</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.gmall</groupId>
<artifactId>gmall-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.gmall</groupId>
<artifactId>gmall-user-v2</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
1.2 gmall-interface项目
根据dubbo分包原则,定义的公共接口层(model,service,exception…),其项目结构如下:
pom.xml文件内容如下:
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.gmall</groupId>
<artifactId>dubbo-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>gmall-interface</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
OrderInfo.java文件,用于整合测试的实体类,内容如下:
package com.gmall.bean;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain=true)
@NoArgsConstructor
@AllArgsConstructor
public class OrderInfo implements Serializable{
private static final long serialVersionUID = 1L;
private Long id;
private String userName;
private String shopName;
private Double price;
private String version;
}
OrderService.java文件,用于测试的公共接口,内容如下:
package com.gmall.api;
import java.util.List;
import com.gmall.bean.OrderInfo;
public interface OrderService {
List<OrderInfo> findList();
}
1.3 gmall-user项目
服务提供者,此项目中包含了在gmall-interface中定义的接口的具体实现,其中OrderServiceImplV1和OrderServiceImplV2是OrderService的两个不同实现,是为了测试dubbo的灰度测试而建立的,其工程结构如下:
pom.xml文件内容如下(需要引入springboot相关依赖和dubbo相关依赖):
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.gmall</groupId>
<artifactId>dubbo-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>gmall-user</artifactId>
<dependencies>
<dependency>
<groupId>com.gmall</groupId>
<artifactId>gmall-interface</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 引入dubbo -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
springboot配置文件application.properties内容如下:
#服务启动端口
server.port=3001
#dubbo服务名称,不同的服务应设置不同的名称
dubbo.application.name=gmall-user
#dubbo注册中心,这里使用zookeeper
dubbo.registry.protocol=zookeeper
#zookeeper连接地址
dubbo.registry.address=zk.com:2181
#RPC通信协议
dubbo.protocol.name=dubbo
#dubbo通信端口,默认20880, -1表示随机端口
dubbo.protocol.port=-1
OrderServiceImplV1.java内容如下(OrderServiceImplV2内容相同,不再重复说明):
package com.gmall.service.impl;
import java.util.List;
import org.assertj.core.util.Lists;
import com.alibaba.dubbo.config.annotation.Service;
import com.gmall.api.OrderService;
import com.gmall.bean.OrderInfo;
//@Service(version = "1.0.0")
@Service //此注解是 com.alibaba.dubbo.config.annotation.Service 下的注解,并非springboot下的@Service注解,若当前实现类需要交由springboot管理,建议使用@Component注解
public class OrderServiceImplV1 implements OrderService {
@Override
public List<OrderInfo> findList() {
System.err.println("I'M 1.0.0 ==============");
OrderInfo o1 = new OrderInfo(1L, "Tom", "笔记本", 12.5D, "1.0.0");
OrderInfo o2 = new OrderInfo(2L, "Jack", "铅笔", 3.5D, "1.0.0");
OrderInfo o3 = new OrderInfo(3L, "Lily", "橡皮", 5.0D, "1.0.0");
return Lists.newArrayList(o1, o2, o3);
}
}
1.4 gmall-user-v2项目
服务提供者,此项目是为测试dubbo的服务集群的负载均衡而创建的,其内容与gmall-user一样,这里不再重复说明,其工程结构如下:
1.5 gmall-web项目
服务消费者,模拟的服务消费者,主要完成远程服务的调用,其中OrderServiceStub.java是为验证dubbo的本地存根建立的,其工程结构如下:
pom.xml文件内容如下(需要引入springboot相关依赖和dubbo相关依赖):
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.gmall</groupId>
<artifactId>dubbo-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>gmall-web</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.gmall</groupId>
<artifactId>gmall-interface</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 引入dubbo -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
springboot配置文件application.properties内容如下:
server.port=3003
dubbo.application.name=gmall-web
dubbo.registry.protocol=zookeeper
dubbo.registry.address=zk.com:2181
OrderServiceStub.java文件内容如下:
package com.gmall.service.stub;
import java.util.List;
import com.gmall.api.OrderService;
import com.gmall.bean.OrderInfo;
/**
* OrderService的本地存根实现
* @Author Jun
* @date 2019年12月2日 下午5:43:23
*/
public class OrderServiceStub implements OrderService {
private OrderService orderService;
/**
* 有参构造 dubbo会自动将远程OrderService注入进来
* @param orderService
*/
public OrderServiceStub(OrderService orderService) {
super();
this.orderService = orderService;
}
/**
* 在远程调用前可以进行判断
*/
@Override
public List<OrderInfo> findList() {
double i = Math.random();
System.err.println("random =============> " + i);
/*if(i > 0.5) {
throw new RuntimeException();
}*/
return orderService.findList();
}
}
WebService.java文件内容如下:
package com.gmall.web;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.dubbo.config.annotation.Reference;
import com.gmall.api.OrderService;
import com.gmall.bean.OrderInfo;
@RestController
public class WebService {
//@Reference dubbo注解
@Reference(stub="com.gmall.service.stub.OrderServiceStub", check=false)
private OrderService orderService;
@GetMapping("/list")
public List<OrderInfo> list() {
return orderService.findList();
}
}
至此,项目已经创建结束。
3. 项目启动
项目启动步骤如下:
1. 启动zookeeper
2. 启动监控中心
3. 启动服务提供者:gmall-user、gmall-user-v2
4. 启动服务消费者:gmall-web
5. 在浏览器输入:http://localhost:3003/list,若出现如下结果,则表示dubbo项目创建并启动成功:
6. 在浏览器输入:http://localhost:8080,若出现如下界面,则表示dubbo服务已成功注册到zookeeper,且可正常监控:
7. 查看各服务之间的关系