array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 微服务架构基础之构建微服务 - 爱码网

学习微服务架构,不但要了解微服务中的基本概念和重要组件,更重要的是实践。本文将会以一个电商中的常见业务场景为例构建微服务。在本文中,主要使用最新的SpringCloud( version:Finchley.SR1)体系进行构建。

1 准备

在开始本文之前,需要以下预备知识:

熟悉Spring和SpringBoot

了解微服务

本文会使用SpringCloud中的一些组件进行开发:

Spring Cloud Netflix Eureka:注册中心

Spring Cloud Netflix Zuul:API网关

Spring Cloud OpenFeign: 服务调用工具

2 业务场景

为了更好的展示微服务,本文将以电商业务场景中的 创建订单 为例。现实系统中的下单非常复杂,这里会进行简化,主要是为了方便理解微服务。所以,这里假定,下单过程中的两个主要操作:

根据下单用户的id,查询当前用户的信息

根据下单的商品id,查询当前商品的信息

最终,根据这个业务场景,设计的微服务架构图如下:


微服务架构基础之构建微服务

按照业务场景,将不同的功能垂直划分成三个服务:

UserService

OrderService

ProductService

其中,OrderService会调用UserService和ProductService的相关服务,在调用过程中,并不是直接调用,而是通过Eureka去调用它们。外部调用不会直接调用具体的服务,全部都是通过Zuul网关进行调用,此处,Zuul也是通过Eureka去调用具体的服务。

3 构建项目

根据架构图,构建项目骨架。创建一个Maven项目,并且创建五个子模块,pom.xml:

1254.0.067org.springframework.boot8spring-boot-starter-parent92.0.1.RELEASE1011com.no.one12microservice-base13pom141.0-SNAPSHOT1516171.8181920212223org.springframework.cloud24spring-cloud-dependencies25Finchley.SR126pom27import282930313233discovery-server34api-gateway-server35order-service36product-service37user-service383940414243org.springframework.boot44spring-boot-maven-plugin4546474849

在这个pom文件中,我们定义了所使用的SpringCloud以及SpringBoot相关库的版本。同时,在各个模块中,我们将使用 .properties 文件作为项目配置文件,而不使用 .yml 文件。 yml文件虽然层次分明,但是基于缩进的语法,容易出问题。关于这个文件格式的选择,要考虑到个人习惯以及团队内的约定。

3.1 注册中心:Eureka

创建Eureka注册中心,首先要引入依赖,在配置文件 microservice-base\discovery-server\pom.xml :

123org.springframework.cloud4spring-cloud-starter-netflix-eureka-server56

然后创建主类, com.no.one.discovery.DiscoveryApplication

[email protected]@EnableEurekaServer3publicclassDiscoveryApplication{4publicstaticvoidmain(String[] args){5SpringApplication.run(DiscoveryApplication.class, args);6}7}

这是一个SpringBoot应用,关键就在于使用 @EnableEurekaServer 注解。然后,增加相关的配置:

microservice-base\discovery-server\src\main\resources\bootstrap.properties:

1spring.application.name=discovery-server

microservice-base\discovery-server\src\main\resources\application.properties:

1server.port=87612eureka.instance.hostname=localhost34eureka.client.registerWithEureka=false5eureka.client.fetchRegistry=false6eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

这个配置文件中,配置了Eureka服务器的参数。

3.2 API网关: Zuul

引入Zuul的依赖,在配置文件 microservice-base\api-gateway-server\pom.xml :

123org.springframework.cloud4spring-cloud-starter-netflix-eureka-client567org.springframework.cloud8spring-cloud-starter-netflix-zuul910

注意,在Zuul网关中,调用上游服务时,是通过调用Eureka进行的,所以,此处引入eureka-client的依赖。

创建主类 com.no.one.gateway.GatewayApplication.java

[email protected]@[email protected]tion{5publicstaticvoidmain(String[] args){6SpringApplication.run(GatewayApplication.class, args);7}8}

这也是一个SpringBoot应用,关键就在于使用 @EnableZuulProxy 注解,该注解会启用反向代理,后面会看到相关的路由配置。同时,通过 @EnableDiscoveryClient 注解,集成对于Eureka的支持,后续,在配置路由时可以直接使用服务的名字进行。

然后,增加相关配置 microservice-base\api-gateway-server\src\main\resources\bootstrap.properties :

1spring.application.name=api-gateway-server

microservice-base\api-gateway-server\src\main\resources\application.properties:

1server.port=900223eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/45zuul.prefix=/api6zuul.ignoredServices='*'78zuul.routes.user-service.path=/user-service/**9zuul.routes.user-service.serviceId=user-service1011zuul.routes.product-service.path=/product-service/**12zuul.routes.product-service.serviceId=product-service1314zuul.routes.order-service.path=/order-service/**15zuul.routes.order-service.serviceId=order-service

在此处,除了Zuul网关的配置,还配置好相关的路由。

3.3 业务服务

完成基础组件,开始构建具体的业务服务。三个业务组件都是SpringBoot应用,构建方法类似。同时,为了简单起见,支持使用内存数据库,数据库的访问直接使用SpingDataJPA。以构建OrderService为例,首先,创建 microservice-base\order-service\pom.xml 文件,并引入依赖:

1234org.springframework.boot5spring-boot-starter-data-jpa678org.springframework.boot9spring-boot-starter-web10111213org.springframework.cloud14spring-cloud-starter-netflix-eureka-client151617org.springframework.cloud18spring-cloud-starter-openfeign19202122org.projectlombok23lombok242526org.hsqldb27hsqldb2829

主要的配置 microservice-base\order-service\src\main\resources\bootstrap.properties :

1spring.application.name=order-service

以上名字属性,作为服务名注册到Eureka中。

microservice-base\order-service\src\main\resources\application.properties :

1server.port =92002eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

相关的主要Java类:

实体类 microservice-base\order-service\src\main\java\com\no\one\order\model\Order.java :

[email protected]@[email protected](name ="ms_order")4publicclassOrder{[email protected]@GeneratedValue(strategy = GenerationType.IDENTITY)7privateLongid;[email protected](name ="product_name")10privateString productName;[email protected](name ="user_name")13privateString userName;[email protected](name ="price")16privateBigDecimal price;[email protected](name ="created_time")19privateDate createdTime;20}

数据访问 microservice-base\order-service\src\main\java\com\no\one\order\repo\OrderRepo.java :

1publicinterfaceOrderRepoextendsJpaRepository{2}

业务接口 microservice-base\order-service\src\main\java\com\no\one\order\service\OrderService.java

1publicinterfaceOrderService{2Order createOrder(LonguserId,LongproductId);3List listOrder();4}

在实现业务接口之前,要实现对于ProductService和UserService的服务调用。此处,直接使用 Open Feign ,该库可以极大简化对于远程服务的调用,并且,使用SpringMVC里的各种常用注解。

调用ProductService, microservice-base\order-service\src\main\java\com\no\one\order\client\ProductClient.java :

[email protected]("product-service")2publicinterfaceProductClient{[email protected](method = RequestMethod.GET, value ="/products/{id}")4ProductDtogetProduct(@PathVariable("id") Long id);5}

最后,实现 OrderService 中的业务接口 microservice-base\order-service\src\main\java\com\no\one\order\service\impl\OrderServiceImpl.java

[email protected]@RequiredArgsConstructor3publicclassOrderServiceImplimplementsOrderService{45privatefinalOrderRepo orderRepo;6privatefinalUserClient userClient;7privatefinalProductClient productClient;[email protected](Long userId, Long productId){11Order order =newOrder();1213UserDto user = userClient.getUser(userId);14order.setUserName(user.getName());1516ProductDto product = productClient.getProduct(productId);17order.setProductName(product.getName());18order.setPrice(product.getPrice());1920order.setCreatedTime(newDate());21returnorderRepo.save(order);22}[email protected](){26returnorderRepo.findAll();27}28}

在 createOrder 方法中,会调用两个远程的服务,然后,创建订单实体对象,最终数据保存到数据库中。

创建RestAPI, microservice-base\order-service\src\main\java\com\no\one\order\controller\OrderController.java

[email protected]@[email protected]("/orders")4publicclassOrderController{56privatefinalOrderService orderService;[email protected] createOrder(@RequestBodyCreateOrderRequest request){10returnorderService.createOrder(request.getUserId(), request.getProductId());11}[email protected] listOrder(){15returnorderService.listOrder();16}[email protected]{20privateLonguserId;21privateLongproductId;22}23}

ProductService和OrderService的构建类似,不过,我们会给这两个服务增加一些数据,他们会在项目启动时初始化到内存数据库中:

microservice-base\user-service\src\main\resources\data.sql

1INSERTINTOms_userVALUES(1,'Zeus');2INSERTINTOms_userVALUES(2,'Hera');3INSERTINTOms_userVALUES(3,'Hades');

microservice-base\product-service\src\main\resources\data.sql

1INSERTINTOms_productVALUES(1,'iPhone4',99);2INSERTINTOms_productVALUES(2,'iPhone6',999.99);3INSERTINTOms_productVALUES(3,'iPhone8',9999.98);

此时,我们可以借助一些RestAPI测试工具,测试创建订单的接口:

POST http://localhost:9002/api/order-service/orders

HTTP请求的请求体:

1{2"userId":1,3"productId":14}

成功后,返回数据:

1{2"id":1,3"productName":"iPhone4",4"userName":"Zeus",5"price":99,6"createdTime":"2018-08-27T12:17:02.406+0000"7}

4 小结

本文结合一个电商中常见的创建订单这个业务场景,使用微服务架构进行构建。结合之前的微服务架构基础系列文章,理论联系实践,可以更好的理解微服务架构。当然,这是一个简单的例子,现实中的开发往往要更加复杂。

如果你现在在JAVA这条路上挣扎,也想在IT行业拿高薪,可以参加我们的训练营课程,选择最适合自己的课程学习,技术大牛亲授,7个月后,进入名企拿高薪。我们的课程内容有:Java工程化、高性能及分布式、高性能、深入浅出。高架构。性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点。如果你想拿高薪的,想学习的,想就业前景好的,想跟别人竞争能取得优势的,想进阿里面试但担心面试不过的,你都可以来,q群号为:855355016

注:加群要求

1、具有1-5工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加。

2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。

3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。

4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。

5.阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!

相关文章:

  • 2021-08-06
  • 2021-10-11
  • 2019-08-27
  • 2021-02-16
  • 2021-10-05
  • 2018-06-28
  • 2021-12-28
  • 2018-07-20
猜你喜欢
  • 2021-12-23
  • 2019-03-29
  • 2019-10-30
  • 2021-06-29
  • 2021-08-21
  • 2019-06-26
  • 2021-12-23
  • 2021-07-05
相关资源
相似解决方案