网站开发项目建设规范,定西网站建设公司,网站运营难吗,网站建设 源美设计引言
本博客总结微服务开发中各个微服务调用的实现#xff0c;并使用 Nacos 完成服务注册和发现。
文章中会涉及到 maven 的使用#xff0c;以及 spring boot 的一些知识。开发工具采用 IDEA 2020.2。
设计一个电商订单和商品购买微服务#xff0c;实现微服务的注册发现与…引言
本博客总结微服务开发中各个微服务调用的实现并使用 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 version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdorg.morty/groupIdartifactIdshop/artifactIdversion1.0-SNAPSHOT/version!-- 指定父工程--parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.1.5.RELEASE/version/parentpropertiesjava.version1.8/java.versionproject.build.sourceEncodingUTF-8/project.build.sourceEncoding/properties!-- 版本锁定--dependencyManagementdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-dependencies/artifactIdversionGreenwich.SR5/versiontypepom/typescopeimport/scope/dependencydependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-alibaba-dependencies/artifactIdversion2.1.1.RELEASE/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagement
/project
下表展示了 Spring Cloud Alibaba Spring Cloud Spring Boot 兼容关系
Spring Cloud VersionSpring Cloud Alibaba VersionSpring Boot Version---------------------Spring Cloud Hoxton2.2.x.RELEASE2.2.x.RELEASESpring Cloud Greenwich2.1.x.RELEASE2.1.x.RELEASESpring Cloud Finchley2.0.x.RELEASE2.0.x.RELEASESpring Cloud Edgware1.5.x.RELEASE1.5.x.RELEASE
三、创建基础依赖模块
new——Module... 添加必要的依赖
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdshop/artifactIdgroupIdorg.morty/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdshop-common/artifactIddependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.58/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-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 {IdGeneratedValue(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 {IdGeneratedValue(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!-- 依赖基础模块--dependencygroupIdorg.morty/groupIdartifactIdshop-common/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-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?serverTimezoneUTCuseUnicodetruecharacterEncodingutf-8rewriteBatchedStatementstrueusername: 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 JpaRepositoryProduct, 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 JpaRepositoryOrder, 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 客户端--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-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 注册中心地址和端口号