引言

本博客总结微服务开发中各个微服务调用的实现,并使用 Nacos 完成服务注册和发现。

文章中会涉及到 maven 的使用,以及 spring boot 的一些知识。开发工具采用 IDEA 2020.2。

设计一个电商订单和商品购买微服务,实现微服务的注册发现与调用。

一、模块设计

本案例采用电商网站作为展示,涉及到的三个微服务有:shop-user、shop-product、shop-order,还有一个公共依赖模块shop-common。他们的依赖、调用关系如下所示:

shop-user 是用户微服务,端口是807x

shop-product 是商品微服务,端口是808x

shop-order 是订单微服务,端口是809x

三个微服务之间可以通过HTTP请求相互调用业务逻辑。

二、创建Maven父工程

为了便于依赖的管理,和项目维护,在实际生产中,往往通过父工程来管理各个 maven 微服务模块,和maven 依赖模块。

(在这里我需要简单说明一下这个大的maven 工程下面,如何理解各个子模块的关系。案例中包含了三个微服务(shop-user/shop-product/shop-order),和一个公共依赖模块(shop-common),它们都会作为一个 maven 子模块存放到父工程目录下,但实际上,在实际部署的时候,三个微服务是分开部署的,因为三个微服务之间的关系,除了通过父工程来统一维护一些依赖版本之外,没有什么在代码层面的耦合关系。而公共依赖模块则在代码层面耦合到各个模块中,部署之后,也是你中有我的概念。)

首先 New ——> Project ——> Maven ,选择好JDK 版本后,直接Next,跳过 archetype 选项。

填写必要的项目名称和存储位置,maven坐标等信息,点击finish:

idea可以快速为我们创建并打开新项目,由于  Maven 父工程只做版本管理,不需要写任何代码,因此一般都会直接删除 src 目录:

紧接着,我们需要修改父工程 pom 文件。它主要需要负责两件事:1、指定父工程   2、依赖版本的锁定

<?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>org.morty</groupId><artifactId>shop</artifactId><version>1.0-SNAPSHOT</version><!-- 指定父工程--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.5.RELEASE</version></parent><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><!-- 版本锁定--><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Greenwich.SR5</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.1.1.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
</project>

下表展示了 Spring Cloud Alibaba & Spring Cloud & Spring Boot 兼容关系:

Spring Cloud Version Spring Cloud Alibaba Version Spring Boot Version
------- ------- -------
Spring Cloud Hoxton 2.2.x.RELEASE 2.2.x.RELEASE
Spring Cloud Greenwich 2.1.x.RELEASE 2.1.x.RELEASE
Spring Cloud Finchley 2.0.x.RELEASE 2.0.x.RELEASE
Spring Cloud Edgware 1.5.x.RELEASE 1.5.x.RELEASE

三、创建基础依赖模块

new——>Module...

添加必要的依赖:

<?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"><parent><artifactId>shop</artifactId><groupId>org.morty</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>shop-common</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.58</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies>
</project>

创建domain实体类,User、Product、Order,这样,其他三个微服务可以依赖使用:

package com.morty.domain;import lombok.Data;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity(name = "shop_user")
@Data
public class User {@Id// 数据库自增@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer uid;private String username;private String password;private String telephone;
}
package com.morty.domain;import lombok.Data;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Data
@Entity(name = "shop_product")
public class Product {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer pid;private String pname;// 商品价格private Double pprice;// 库存private Integer stock;
}
package com.morty.domain;import lombok.Data;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Data
@Entity(name = "shop_order")
public class Order {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer oid;private Integer uid;private String username;private Integer pid;private String pname;private Double pprice;/** 购买数量*/private Integer number;
}

四、创建微服务模块

依次创建shop-user、shop-product、shop-order 三个微服务,并依赖 shop-common。篇幅有限,以 shop-product 为例。

1、和shop-common的创建方式一样,新建一个 Module,并命名 shop-product,修改pom文件,添加 shop-common依赖和 web starter:

    <dependencies><!-- 依赖基础模块--><dependency><groupId>org.morty</groupId><artifactId>shop-common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>

2、创建spring boot 启动类:

@SpringBootApplication
@Slf4j
public class ProductApplication {public static void main(String[] args) {SpringApplication.run(ProductApplication.class);log.info("-----------启动成功------------");}
}

3、修改配置文件:

server:port: 8081
spring:application:name: service-productdatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=trueusername: rootpassword: 123456jpa:properties:hibernate:hbm2ddl:auto: update# InnoDB方言dialect: org.hibernate.dialect.MySQL5InnoDBDialect

然后就是创建 controller、service、dao:

@Slf4j
@RestController
@RequestMapping("/product")
public class ProductController {@Autowiredprivate ProductService productService;/*** 查询订单信息* @param pid* @return*/@GetMapping("/{pid}")public Product getProduct(@PathVariable("pid") Integer pid) {log.info("收到查询商品信息请求,商品编号:{}", pid);Product product = productService.getProduct(pid);log.info("商品信息查询成功:{}", JSON.toJSONString(product));return product;}
}
@Service
public class ProductService {@Autowiredprivate ProductDao productDao;public Product getProduct(Integer productId) {return productDao.findById(productId).get();}
}
public interface ProductDao extends JpaRepository<Product, Integer> {
}

最后,手动创建 shop 数据库,然后启动服务,可以看到表已经自动创建好了,向 shop_product 表插入一条商品信息:

INSERT INTO `shop_product`(pname, pprice, stock) VALUES('皮大衣', '120', '20');

打开浏览器,访问接口,可以正常返回:

五、微服务调用

按照类似的步骤创建好了三个微服务之后,我们来实现订单到商品的微服务调用。需要说明的是,任何两个服务之间都是可以通过http请求进行调用,而不完全需要服务治理功能,也就是说,如果我们指定了ip和端口号,实际上就可以实现微服务的调用。

为了演示方便,这里只列出关键代码,并去掉了Service的接口层。

提供必要的 restTemplate:

    @Beanpublic RestTemplate restTemplate() {return new RestTemplate();}

DAO:

public interface OrderDao extends JpaRepository<Order, Integer> {
}

Service:

@Service
public class OrderService {@Autowiredprivate OrderDao orderDao;public void createOrder(Order order) {orderDao.save(order);}
}

Controller:

@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate OrderService orderService;/**** 下单* @param pid* @return*/@GetMapping("/prod/{pid}")public Order order(@PathVariable("pid") Integer pid) {log.info("接收到{}号商品的下单请求,准备调用商品微服务", pid);// 调用商品微服务,查询商品信息Product prod = restTemplate.getForObject("http://localhost:8081/product/" + pid, Product.class);log.info("查询到{}号商品信息,内容是:{}", pid, JSON.toJSONString(prod));// 下单(即创建订单并保存)Order order = new Order();order.setUid(1);order.setUsername("测试用户");order.setPid(pid);order.setPname(prod.getPname());order.setPprice(prod.getPprice());order.setNumber(1);// 订单入库orderService.createOrder(order);log.info("创建订单成功,订单信息为:{}", JSON.toJSONString(order));return order;}
}

然后在配置文件中指定 8091 端口号,以及数据库地址等必要信息。启动 OrderApplication 和 ProductApplication,调用 /order/prod/{pid} 接口:

检查控制台打印的日志:

订单微服务:

商品微服务:

同时数据库也出现了刚才添加的订单记录:

六、服务治理

在前面的微服务调用案例中,我们通过 restTemplate 对象,配合 ip + port 的形式,实现了最简单的订单微服务到商品微服务的调用逻辑。

但这在实际生产中会存在较大的问题:

1、一旦服务提供者的地址发生变化,就不得不去修改服务调用者的代码,即便是使用配置文件也治标不治本。

2、在高并发场景中,服务一般需要进行集群部署,会有多个服务提供者实例。那么就需要通过负载均衡调用不同的服务提供者,来分散单个服务实例的访问压力,上面这种调用方式显然无法满足负载均衡的要求。

3、一旦微服务变得越来越多,如果管理服务清单将会是一个大问题。

基于以上几点,就有了服务治理的概念:

服务治理是微服务架构中最核心、最基本的模块。用于实现各个微服务的自动化注册和发现。

服务注册:在服务治理框架中,都会构建一个注册中心。每个服务单元向注册中心登记自己提供服务的详细信息。注册中心会基于这些微服务的详细信息,生成一张服务清单。注册中心需要以心跳的方式检测清单中服务是否可用,如果发现心跳异常的服务,会从服务清单中剔除不可用的服务。

服务发现:服务消费者向注册中心咨询服务,并获取所有服务的实例清单,实现对具体服务的访问。

常用的服务治理框架有:

ZooKeeper:是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要用来解决分布式应用中经常遇到的一些数据管理问题,如统一命名服务、状态同步服务、集群管理、分布式应用配置项管理等。

Eureka:是Spring Cloud Netfix 中的重要组件,主要作用是做服务注册和发现,但现在已经闭源。

Nacos:是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它是 Spring cloud Alibaba 的组件之一,负责服务注册发现和服务配置,可以认为是 Eureka + Config 的组合升级版服务治理框架。

七、Nacos-discovery 实现微服务调用

7.1 启动 Nacos 服务

首先,如果想使用 Nacos 注册中心服务,必须到官网上下载启动压缩包。值得一提的是,原来的 Eureka 是通过 Spring boot 构建一个专门用于实现注册发现的微服务,这需要我们手动去构建这样一个重要的架构组件,但是 Nacos 则提供了独立的启动程序,让开发者可以开箱即用,进一步提高了微服务部署的效率。

nacos 下载地址:https://nacos.io/zh-cn/docs/quick-start.html

不论你是在 Windows 环境上学习和练习,还是在 Linux 服务器上安装部署,都只需要简单的一键启动即可。

启动成功后,我们通过浏览器访问控制台,默认用户名和密码都是 nacos,下图登录成功后进入首页:

7.2 将微服务注册到 Nacos

以 shop-product 为例,演示如何将微服务注册到 Nacos。

1、微服务中添加 nacos 客户端依赖:

        <!-- nacos 客户端--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-nacos-discovery</artifactId></dependency>

2、为主类添加@EnableDiscoveryClient 注解:

@Slf4j
@EnableDiscoveryClient
@SpringBootApplication
public class ProductApplication {public static void main(String[] args) {SpringApplication.run(ProductApplication.class);log.info("-----------启动成功------------");}
}

3、配置 Nacos Server 地址:

spring:cloud:nacos:discovery:server-addr: localhost:8848

4、启动微服务,查看 Nacos 控制台:

7.3 Nacos 实现微服务调用

针对前面第五节订单到商品的微服务调用方式,我们调整一下restTemplate 代码,以服务治理推荐的方式来实现微服务调用。

引入服务发现客户端对象:

@Autowired
private DiscoveryClient discoveryClient;

修改代码:

启动 shop-order 、shop-product 微服务,它们会自动注册到 Nacos 中。

重新调用下单接口,可以看到接口依然调用成功:

总结

微服务注册中心的主要功能是负责服务注册发现,它会生成一张注册服务清单,可以简单理解为一个服务名称和对应服务地址的对照表,服务消费者使用服务名称调用服务提供者的接口时,会直接发送到对应地址:

微服务如果想要注册到 Nacos Server,需要完成三件事:

1、添加 nacos-discovery 依赖

2、启动服务发现客户端,即添加 @EnableDiscoveryClient 注解到主类

3、配置 Nacos server 注册中心地址和端口号

Spring Cloud Alibaba——Nacos实现服务治理相关推荐

  1. 【深入了解Spring Cloud Alibaba Nacos:服务注册和配置中心】—— 每天一点小知识

  2. Spring Cloud Alibaba —— Nacos Config 配置中心

    导航 引言 一.什么是配置中心 二.常见的配置中心组件 三.Nacos Config 入门 四.Nacos Config 动态配置 4.1 硬编码方式(默认支持动态生效) 4.2 属性注入 五.配置共 ...

  3. Spring Cloud 微服务开发:入门、进阶与源码剖析 —— 11.1 Spring Cloud Alibaba Nacos 概述

    11.1 Spring Cloud Alibaba Nacos 概述 11.1.1 Spring Cloud Alibaba 简介 在一开始,我们先简单介绍下Spring Cloud Alibaba的 ...

  4. 用Spring Cloud Alibaba开发微服务会更香吗?

    关注DD,除了前沿消息,还有每周福利哦 Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案,它是Spring Cloud组件被植入Alibaba元素之后的产物. 利用Spri ...

  5. 流量暴增,掌门教育如何基于 Spring Cloud Alibaba 构建微服务体系?

    作者 | 童子龙  掌门教育基础架构部架构师 **导读:**本文整理自作者于 2020 年云原生微服务大会上的分享<掌门教育云原生落地实践>,本文主要介绍了掌门教育云原生落地实践,主要围绕 ...

  6. Spring Cloud Alibaba 大型微服务项目实战

    作者介绍 程序员十三,多年一线开发经验,历任高级开发工程师.后端主程.技术部门主管等职位.同时也是开源项目的爱好者和贡献者.掘金优秀作者.CSDN 博客专家.实体图书作者.专栏作者.视频讲师. 小册介 ...

  7. 进击的 Spring Cloud Alibaba —— 框架与服务

    作者 | 陈曦(良名)  Spring Cloud Alibaba 项目成员,start.aliyun.com 负责人. 导读:本文整理自作者于 2020 年云原生微服务大会上的分享<进击的 S ...

  8. Spring Cloud Alibaba Nacos Confifig是什么

    Spring Cloud Alibaba Nacos Confifig是Spring Cloud Alibaba的子项目,而Spring Cloud Alibaba是阿里巴巴公司提供的开源的基于Spr ...

  9. Spring Cloud Alibaba Nacos 的 2 种健康检查机制!

    作者 | 磊哥 来源 | Java中文社群(ID:javacn666) 转载请联系授权(微信ID:GG_Stone) Spring Cloud Alibaba Nacos 作为注册中心不止提供了服务注 ...

最新文章

  1. PHP 常用字符串处理代码片段
  2. 各国自动驾驶政策概况及特征
  3. 阶段-关系系统-stage1范围界定阶段---学习记录
  4. 1.17.Flink 并行度详解(Parallel)、TaskManager与Slot、Operator Level、Execution Environment Level、Client Level等
  5. 面向对象(final/抽象类/接口/内部类)
  6. 沉默十个月 前锤子科技副总裁发声:坚持为粉丝做手机
  7. @程序员,这些编程陷阱你中招了吗?
  8. 程序中try、throw、catch三者之间的关系
  9. 到底谁才是苹果公司实际控制人?
  10. Qt5,信号槽关联错误
  11. 商住楼和住宅楼的区别
  12. Spring-cloud学习教程视频
  13. 二叉搜索树(kv模型)的模拟实现
  14. t480 拆触摸板_用料不错 ThinkPad翼480笔记本拆机解析
  15. 大厂面试通行证- Java基础
  16. 【有感】成为一个不惑、不忧、不惧的人
  17. 【干货】PCB线宽与电流关系
  18. 微软蓝牙鼠标卡顿问题解决
  19. 自动控制原理(根轨迹)
  20. oracle验证手机号sql,oracle判断手机号码是否合法

热门文章

  1. 机器学习 导论_机器学习导论
  2. Java LineNumberReader getLineNumber()方法及示例
  3. 玩转Nacos参数配置!多图勿点
  4. SpringBoot时间格式化的5种方法!
  5. 2万字长文包教包会 JVM 内存结构
  6. 如何系统学习python
  7. 部署虚拟环境安装Linux系统(Linux就该这么学)笔记
  8. mysql多表联查到新的表中_MySQL中的多表联查
  9. 刘卫国python实验答案_MATLAB(刘卫国)部分实验答案
  10. java inireader_java读取配置文件 Java中如何设置读取ini配置文件?