您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
   
 
     
   
 订阅
  捐助
利用springboot+dubbo,构建分布式微服务,全程注解开发
 
作者:鸭血粉丝
169 次浏览     评价:  
 2020-9-9  
   
 
编辑推荐:
本文主要是介绍 Springboot 与 Dubbo 的框架整合以及开发实践,我们以一个用户选择商品下订单这个流程,将其拆分成3个业务服务。
本文来自于微信 Java极客技术,由火龙果软件Anna编辑、推荐。

随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。

一、先来一张图

说起 Dubbo,相信大家都不会陌生!阿里巴巴公司开源的一个高性能优秀的服务框架,可以使得应用可通过高性能的 RPC 实现服务的输出和输入功能,同时可以和 Spring 框架无缝集成。

Dubbo 架构图

节点角色说明:

Provider:暴露服务的服务提供方

Consumer:调用远程服务的服务消费方

Registry:服务注册与发现的注册中心

Monitor:统计服务的调用次数和调用时间的监控中心

Container:服务运行容器

二、实现思路

今天,我们以一个用户选择商品下订单这个流程,将其拆分成3个业务服务:用户中心、商品中心、订单中心,使用 Springboot + Dubbo 来实现一个小 Demo!

服务交互流程如下:

本文主要是介绍 Springboot 与 Dubbo 的框架整合以及开发实践,而真实的业务服务拆分是一个非常复杂的过程,比我们介绍的这个要复杂的多,上文提到的三个服务只是为了项目演示,不必过于纠结为什么要这样拆分!

好了,废话也不多说了,下面我们开撸!

1.在虚拟机创建 4 台 centos7,任意选择一台安装 zookeeper

2.构建微服务项目并编写代码

3.在 centos7 上部署微服务

4.远程服务调用测试

三、zookeeper安装

在使用 Dubbo 之前,我们需要一个注册中心,目前 Dubbo 可以选择的注册中心有 zookeeper、Nacos 等,一般建议使用 zookeeper!

首先在安装 Zookeeper 之前,需要安装并配置好 JDK,本机采用的是Oracle Java8 SE。

安装JDK(已经安装可以忽略)

yum -y install java-1.8.0-openjdk

查看java安装情况

java -version

JDK安装完成之后,下载安装Zookeeper

#创建一个zookeeper文件夹
cd /usr
mkdir zookeeper
#下载zookeeper-3.4.14版本
wget http://mirrors.hust.edu.cn/ apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
#解压
tar -zxvf zookeeper-3.4.14.tar.gz

创建数据、日志目录


#创建数据和日志存放目录
cd /usr/zookeeper/
mkdir data
mkdir log
#把conf下的zoo_sample.cfg备份一份,然后重命名为zoo.cfg
cd conf/
cp zoo_sample.cfg zoo.cfg
 

配置zookeeper

#编辑zoo.cfg文件
vim zoo.cfg

启动Zookeeper


#进入Zookeeper的bin目录
cd zookeeper/zookeeper-3.4.14/bin
#启动Zookeeper
./zkServer.sh start
#查询Zookeeper状态
./zkServer.sh status
#关闭Zookeeper状态
./zkServer.sh stop

出现如下信息,表示启动成功!

四、项目介绍

springboot版本:2.1.1.RELEASE

zookeeper版本:3.4.14

dubbo版本:2.7.3

mybtais-plus版本:3.0.6

数据库:mysql-8

构建工具:maven

服务模块:用户中心、商品中心、订单中心

五、代码实践

5.1、初始化数据库

首先在 mysql 客户端,创建3个数据库,分别是:dianshang-user、dianshang-platform、dianshang-business。

在 dianshang-user 数据库中,创建用户表 tb_user,并初始化数据

在 dianshang-platform 数据库中,创建商品表 tb_product,并初始化数据

在 dianshang-platform 数据库中,创建订单表 tb_order、订单详情表 tb_order_detail

5.2、创建工程

数据库表设计完成之后,在 IDEA 下创建一个名称为dianshang的Springboot工程。

最终的目录如下图:

目录结构说明:

dianshang-common:主要存放一些公共工具库,所有的服务都可以依赖使用

dianshang-business:订单中心,其中api模块主要是提供dubbo服务暴露接口,provider模块是一个springboot项目,提供服务处理操作

dianshang-user:用户中心,其中api模块和provider模块,设计与之类似

dianshang-platform:商品中心,其中api模块和provider模块,设计与之类似

在父类pom文件中加入dubbo和zookeeper客户端,所有依赖的项目都可以使用。

<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId> dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<!-- 因为使用的是 zookeeper 作为注册中心,所以要添加 zookeeper 依赖 -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--使用curator 作为zookeeper客户端-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework </artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator </groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>

温馨提示:小编在搭建环境的时候,发现一个坑,工程中依赖的zookeeper版本与服务器的版本,需要尽量一致,例如,本例中zookeeper服务器的版本是3.4.14,那么在依赖zookeeper文件库的时候,也尽量保持一致,如果依赖3.5.x版本的zookeeper,项目在启动的时候会各种妖魔鬼怪的报错!

5.3、创建用户中心项目

在 IDEA 中,创建dianshang-user子模块,并依赖dianshang-common模块

<dependencies>
<dependency>
<groupId>org.project.demo</groupId>
<artifactId>dianshang-common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>

同时,创建dianshang-user-provider和dianshang-user-api模块。

dianshang-user-api:主要对其他服务提供接口暴露

dianshang-user-provider:类似一个web工程,主要负责基础业务的crud,同时依赖dianshang-user-api模块

5.3.1、配置dubbo服务

在dianshang-user-provider的application.yml文件中配置dubbo服务,如下:


#用户中心服务端口
server:
port: 8080
#数据源配置
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: "jdbc: mysql://localhost:3306/dianshang-user"
username: root
password: 111111
#dubbo配置
dubbo:
scan:
# 包名根据自己的实际情况写
base-packages: org.project.dianshang.user
protocol:
port: 20880
name: dubbo
registry:
#zookeeper注册中心地址
address: zookeeper://192.168.0.107:2181

5.3.2、编写服务暴露接口以及实现类

在dianshang-user-api模块中,创建一个UserApi接口,以及返回参数对象UserVo!


public interface UserApi {
/**
* 查询用户信息
* @param userId
* @return
*/
UserVo findUserById(String userId);
}

其中UserVo,需要实现序列化,如下:


@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class UserVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 用户ID
*/
private String userId;
/**
* 用户中文名
*/
private String userName;
}

在dianshang-user-provider模块中,编写UserApi接口实现类,如下:


@Service(interfaceClass =UserApi.class)
@Component
public class UserProvider implements UserApi {
@Autowired
private UserService userService;
@Override
public UserVo findUserById(String userId) {
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.eq ("user_id",userId);
User source = userService.getOne(queryWrapper);
if(source != null){
UserVo vo = new UserVo();
BeanUtils.copyProperties(source,vo);
return vo;
}
return null;
}
}

其中的注解@Service指的是org.apache.dubbo.config.annotation.Service下的注解,而不是Spring下的注解哦!

接着,我们继续创建商品中心项目!

5.4、创建商品中心项目

与用户中心项目类似,在 IDEA 中,创建dianshang-platform子模块,并依赖dianshang-common模块

<dependencies>
<dependency>
<groupId>org.project.demo</groupId>
<artifactId>dianshang-common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>

同时,创建dianshang-platform-provider和dianshang-platform-api模块。

dianshang-platform-api:主要对其他服务提供接口暴露

dianshang-platform-provider:类似一个web工程,主要负责基础业务的crud,同时依赖dianshang-platform-api模块

5.4.1、配置dubbo服务

在dianshang-platform-provider的application.yml文件中配置dubbo服务,如下:

#用户中心服务端口
server:
port: 8081
#数据源配置
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: "jdbc: mysql://localhost:3306/dianshang -platform"
username: root
password: 111111
#dubbo配置
dubbo:
scan:
# 包名根据自己的实际情况写
base-packages: org.project.dianshang.platform
protocol:
port: 20881
name: dubbo
registry:
#zookeeper注册中心地址
address: zookeeper://192.168.0.107:2181

5.4.2、编写服务暴露接口以及实现类

在dianshang-platform-api模块中,创建一个ProductApi接口,以及返回参数对象ProductVo!

public interface ProductApi {
/**
* 通过商品ID,查询商品信息
* @param productId
* @return
*/
ProductVo queryProductInfoById (String productId);
}

其中ProductVo,需要实现序列化,如下:


@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class ProductVo implements Serializable {
private static final long serialVersionUID = 1L;
/**商品ID*/
private String productId;
/**商品名称*/
private String productName;
/**商品价格*/
private BigDecimal productPrice;
}

在dianshang-platform-provider模块中,编写ProductApi接口实现类,如下:


@Service(interfaceClass = ProductApi.class)
@Component
public class ProductProvider implements ProductApi {
@Autowired
private ProductService productService;
@Override
public ProductVo queryProductInfoById(String productId) {
//通过商品ID查询信息
Product source = productService.getById(productId);
if(source != null){
ProductVo vo = new ProductVo();
BeanUtils.copyProperties(source,vo);
return vo;
}
return null;
}
}

接着,我们继续创建订单中心项目!

5.5、创建订单中心项目

与商品中心项目类似,在 IDEA 中,创建dianshang-business子模块,并依赖dianshang-common模块

<dependencies>
<dependency>
<groupId>org.project.demo</groupId>
<artifactId>dianshang-common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>

同时,创建dianshang-business-provider和dianshang-business-api模块。

dianshang-business-api:主要对其他服务提供接口暴露

dianshang-business-provider:类似一个web工程,主要负责基础业务的crud,同时依赖dianshang-business-api模块

5.5.1、配置dubbo服务

在dianshang-business-provider的application.yml文件中配置dubbo服务,如下:

#用户中心服务端口
server:
port: 8082
#数据源配置
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: "jdbc: mysql://localhost:3306/dianshang -business"
username: root
password: 111111
#dubbo配置
dubbo:
scan:
# 包名根据自己的实际情况写
base-packages: org.project.dianshang.business
protocol:
port: 20882
name: dubbo
registry:
#zookeeper注册中心地址
address: zookeeper://192.168.0.107:2181

5.5.2、编写服务暴露接口以及实现类

在dianshang-business-api模块中,创建一个OrderApi接口,以及返回参数对象OrderVo!


public interface OrderApi {
/**
* 通过用户ID,查询用户订单信息
* @param userId
* @return
*/
List<OrderVo> queryOrderByUserId(String userId);
}

其中OrderVo,需要实现序列化,如下:

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class OrderVo implements Serializable {
private static final long serialVersionUID = 1L;
/**订单ID*/
private String orderId;
/**订单编号*/
private String orderNo;
/**订单金额*/
private BigDecimal orderPrice;
/**下单时间*/
private Date orderTime;
}
 

在dianshang-business-provider模块中,编写OrderApi接口实现类,如下:


@Service(interfaceClass = OrderApi.class)
@Component
public class OrderProvider implements OrderApi {
@Autowired
private OrderService orderService;
@Override
public List<OrderVo> queryOrderByUserId(String userId) {
QueryWrapper<Order> queryWrapper = new QueryWrapper<Order>();
queryWrapper.eq("user_id",userId);
List<Order> sourceList = orderService.list(queryWrapper);
if(!CollectionUtils.isEmpty(sourceList)){
List<OrderVo> voList = new ArrayList<>();
for (Order order : sourceList) {
OrderVo vo = new OrderVo();
BeanUtils.copyProperties( order, vo);
voList.add(vo);
}
return voList;
}
return null;
}
}

至此,3个项目的服务暴露接口已经开发完成!接下来我们来编写怎么进行远程调用!

5.6、远程调用

5.6.1、编写创建订单服务

在dianshang-business-provider模块中,编写创建订单接口之前,先依赖dianshang-business-api和dianshang-user-api,如下:

<!--商品服务接口暴露 api-->
<dependency>
<groupId>org.project.demo</groupId>
<artifactId>dianshang -platform-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--用户服务接口暴露 api-->
<dependency>
<groupId>org.project.demo</groupId>
<artifactId>dianshang -user-api</artifactId>
<version>1.0.0</version>
</dependency>

在dianshang-business-provider模块中,编写创建订单服务,如下:

@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private OrderDetailService orderDetailService;
@Reference(check =false)
private ProductApi productApi;
@Reference(check =false)
private UserApi userApi;
/**
* 新增
*/
@JwtIgnore
@RequestMapping(value = "/add")
public boolean add(String productId,String userId){
LocalAssert.isStringEmpty (productId,"产品Id不能为空");
LocalAssert.isStringEmpty (userId,"用户Id不能为空");
ProductVo productVo = productApi.queryProductInfoById(productId);
LocalAssert.isObjectEmpty (productVo,"未查询到产品信息");
UserVo userVo = userApi.findUserById(userId);
LocalAssert.isObjectEmpty (userVo,"未查询到用户信息");
Order order = new Order();
order.setOrderId (IdGenerator.uuid());
order.setOrderNo (System.currentTimeMillis() + "");
order.setOrderPrice(productVo.getProductPrice());
order.setUserId(userId);
order.setOrderTime(new Date());
orderService.save(order);
OrderDetail orderDetail = new OrderDetail();
orderDetail.setOrderDetailId (IdGenerator.uuid());
orderDetail.setOrderId (order.getOrderId());
orderDetail.setProductId (productId);
orderDetail.setSort(1);
orderDetailService.save (orderDetail);
return true;
}
}

其中的@Reference注解,是属于org.apache.dubbo.config. annotation.Reference下的注解,表示远程依赖服务。

参数check =false表示启动服务时,不做远程服务状态检查,这样设置的目的就是为了防止当前服务启动不了,例如用户中心项目没有启动成功,但是订单中心又依赖了用户中心,如果check=true,此时订单中心启动会报错!

5.6.2、编写用户查询自己的订单信息

同样的,在dianshang-user-provider模块中,编写用户查询自己的订单信息接口之前,先依赖dianshang-business-api和dianshang-user-api,如下:

<dependency>
<groupId>org.project.demo</groupId>
<artifactId>dianshang-business-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.project.demo</groupId>
<artifactId>dianshang-user-api</artifactId>
<version>1.0.0</version>
</dependency>

在dianshang-user-provider模块中,编写用户查询自己的订单信息接口,如下:

@RestController
@RequestMapping("/user")
public class UserController {
@Reference(check =false)
private OrderApi orderApi;
/**
* 通过用户ID,查询订单信息
* @param userId
* @return
*/
@RequestMapping("/list")
public List<OrderVo> queryOrderByUserId(String userId){
return orderApi.queryOrderByUserId( userId);
}
}

至此,远程服务调用,编写完成!

六、服务测试

在将项目部署在服务器之前,咱们先本地测试一下,看服务是否都可以跑通?

启动用户中心dianshang-user-provider

继续启动商品中心dianshang-platform-provider

接着启动订单中心dianshang-business-provider

最后,我们来测试一下服务接口是否为我们预期的结果?

打开浏览器,输入http://127.0.0.1:8082/order/add? productId=1&userId=1测试创建订单接口,页面运行结果显示正常!

我们再来看看数据库,订单是否生成?

ok!很清晰的看到,数据已经进去了,没啥问题!

我们再来测试一下在用户中心订单查询接口,输入http://127.0.0.1: 8080/user/list?userId=1,页面运行结果如下!

到此,本地服务测试基本通过!

七、服务器部署

在上文中,我们介绍了服务的构建、开发和测试,那如何在服务器端部署呢?

首先,修改各个项目的application.yml文件,将其中的数据源地址、dubbo注册中心地址修改为线上能联通的地址,然后在dianshang目录下使用maven工具对整个工程执行如下命令进行打包!

mvn clean install

也可以在 IDEA 环境下,通过maven配置clean install命令执行打包。

将各个项目target目录下的dianshang-user-provider.jar、dianshang-platform-provider.jar、dianshang-business-provider.jar拷贝出来。

分别上传到对应的服务器目录,本服务器采用的是 CentOS7,总共4台服务器,其中一台部署zookeeper,另外三台部署三个微服务项目。

登录服务器,输入如下命令,确保JDK已经安装完成!

java -version

关闭所有服务器的防火墙,放行端口访问!

#关闭防火墙
systemctl stop firewalld.service
#禁止开机启动
systemctl disable firewalld.service

启动用户中心服务,日志信息输出到service.log(虚拟机ip:192.168.0.108)

nohup java -jar dianshang-user-provider.jar > service.log 2>&1 &

启动商品中心服务,日志信息输出到service.log(虚拟机ip:192.168.0.107)

nohup java -jar dianshang-platform-provider.jar > service.log 2>&1 &

启动订单中心服务,日志信息输出到service.log(虚拟机ip:192.168.0.109)

nohup java -jar dianshang-business-provider.jar > service.log 2>&1 &

打开浏览器,输入http://192.168.0.109:8082/ order/add?productId= 1&userId=1测试创建订单接口,页面运行结果显示正常!

我们再来测试一下在用户中心订单查询接口,输入输入http://192.168.0.108: 8080/user/list ?userId=1,页面运行结果如下!

很清晰的看到,输出了2条信息,第二条订单是在测试环境服务器生成的,第一条是本地开发环境生成的。

到此,服务器部署基本已经完成!

如果是生产环境,可能就需要多台zookeeper来保证高可用,至少2台服务器来部署业务服务,通过负载均衡来路由!

八、总结

整片文章比较长,主要是围绕 springboot + dubbo 的整合,通过注解开发实现远程服务调用像传统的 springmvc 开发一样轻松,当然还可以通过xml配置方式实现dubbo服务的调用,这个会在后期去介绍。

同时也介绍了服务器的部署,从中可以看出,开发虽然简单,但是由于分布式部署,如何保证服务高可用成了开发人员头等工作任务,所以,分布式微服务开发虽然开发简单,但是如何确保部署的服务高可用?运维方面会带来不少的挑战!

九、参考

1、apache - dubbo - 官方文档

 
   
169 次浏览     评价: 订阅 捐助
相关文章

阻碍使用企业架构的原因及克服方法
世界级企业架构的行业挑战
企业架构和SOA架构的角色将融合
什么最适合您的组织?
相关文档

企业架构与ITIL
企业架构框架
Zachman企业架构框架简介
企业架构让SOA落地
相关课程

企业架构设计
软件架构案例分析和最佳实践
嵌入式软件架构设计—高级实践
企业级SOA架构实践
最新课程计划
 
最新文章
大数据平台下的数据治理
如何设计实时数据平台(技术篇)
大数据资产管理总体框架概述
Kafka架构和原理
ELK多种架构及优劣
最新课程
大数据平台搭建与高性能计算
大数据平台架构与应用实战
大数据系统运维
大数据分析与管理
Python及数据分析
更多...   
成功案例
某通信设备企业 Python数据分析与挖掘
某银行 人工智能+Python+大数据
北京 Python及数据分析
神龙汽车 大数据技术平台-Hadoop
中国电信 大数据时代与现代企业的数据化运营实践
更多...