微服务体系结构是构建现代软件系统最流行的方法之一。微服务体系结构的核心是使用更小的内聚服务构建软件应用程序。您不需要构建一个大型的整体,而是构建小型的可独立部署的服务。因此,单个团队可以拥有端到端的功能。
什么是微服务体系结构?
微服务体系结构由许多(通常是数百个)小型自治服务组成。每项服务都是独立的。微服务是围绕业务能力构建的。微服务体系结构的一些重要特征包括:
- 微服务是围绕业务能力建模的。
- 微服务是可独立部署的。
- 微服务封装了它所拥有的数据。如果一个微服务需要从另一个微服务获取数据,那么它应该调用API。
- 微服务的规模应该很小。
Java微服务的事实标准是Spring Boot。
什么是Spring Boot?
SpringBoot是构建微服务最流行的框架之一。它带有智能默认值。创建微服务就像定义几个依赖项一样简单。对嵌入式web服务器的SpringBoot支持使编写RESTFul API变得非常容易。您可以通过一些配置集成其他框架。
构建微服务的秘诀
在本文中,我将讨论如何使用SpringBoot构建一个真实的微服务。首先,我将解释如何识别微服务边界。之后,我将解释如何使用API优先方法设计API。然后,我将解释如何在Kubernetes上编码和部署微服务。在这个过程中,我将涉及
围绕业务能力构建微服务
微服务体系结构的主要好处之一是开发人员的灵活性。它使产品团队能够更灵活地构建更小的功能增量。因此,以相互独立的方式设计微服务非常重要。围绕业务能力建模微服务就是这样一种设计技术。
围绕业务能力构建微服务的技术之一是使用域驱动设计(DDD)。Eric Evans在他的书《领域驱动设计》中推广了DDD。
DDD是对复杂业务领域进行建模并将其分解为可管理子域和有界上下文的框架。
让我们从DDD的角度来看电子商务领域。电子商务领域可以由以下子域和有界上下文组成。
DDD分为两个阶段:
- 战略设计:在战略设计中,您将重点放在整个业务领域。您可以识别有界上下文、子域、通用语言以及不同有界上下文之间的上下文映射。
- 战术设计:战术设计为您提供了一组设计模式来建模业务领域。在战术设计期间,您可以识别实体、服务、聚合根、存储库等。
DDD是一个迭代过程。这通常包括领域专家、开发人员和其他涉众。
在DDD中,识别微服务的过程可以如下所示:
“聚合根”可以是微服务的一个很好的候选者,因为它代表事务边界内的一个功能上内聚的单元。此外,域服务是无状态的,可以成为微服务的另一个很好的候选者。
DDD术语
- 领域:公司的整体业务领域。
- 子域:业务域的细粒度区域。所有子域加起来就是公司的业务域。
- 泛在语言:团队、开发人员、领域专家和其他参与者共享的语言。
- 有界上下文:域中业务上下文的逻辑边界。
- 实体:具有标识的域对象。例如,可以使用产品id识别产品。
- 价值对象:由其价值标识的对象(例如,货币)。
- 聚合:表示对象的hirearchy的根实体。通常,它表示事务边界。
- 服务:一个对象,它实现了一些不适合单个实体的逻辑。服务是无状态的。
- 存储库:从数据存储中检索或持久化域对象的对象。
- 工厂:工厂是一个对象,具有直接创建域对象的方法。
DDD与Event Storming
事件风暴是一种基于DDD实施技术。这是一种轻量级和有效的领域建模方法。事件风暴研讨会涉及开发人员、领域专家和其他利益相关者。它基于识别域事件和导致这些域事件的命令。参与者使用便签记录事件、命令、聚合等。
领域事件是领域专家感兴趣的任何重要事件。领域专家对实现细节(如数据库、web套接字或设计模式)不感兴趣。领域专家对必须发生的事情的业务领域更感兴趣。域事件以不指定特定实现的方式捕获这些事实。您可以使用橙色便笺标记时间线中的事件。
概述事件后,您可以开始评估每个事件的原因和后果。事件可以由用户或外部系统触发。例如,用户从购物车中签出产品可以触发“产品签出”事件。
事件风暴研讨会的目标之一是确定集合。聚合接受导致域事件的命令。然后,将聚合分组到有界上下文中。在此过程中,您可以确定用户、数据、UI和用户目标。最后,您将发现有界上下文之间的关系。
电子商务领域的事件风暴研讨会的结果如下所示。这并不是一个完整的画面——只是我在思考事件,而不是一个涉及领域专家和其他利益相关者的研讨会。
如上所述,聚合和应用程序服务可以很好地应用于微服务。在事件风暴研讨会之后,您可以将一些微服务确定为:
1. 为产品管理提供Product Catalog产品目录服务。
2. 用于购物车管理的Cart Service购物车服务。
3. 订单管理的Order Service订单服务
4. 等等
设计API
识别微服务之后,您需要设计应用程序编程接口(API)。API是应用程序的接口。API允许您的应用程序与其他应用程序通信,而无需知道实现。最近,API优先设计已经成为设计API的流行方法之一。
简而言之,API优先的方法假设API的设计和开发先于实现。在设计并记录API之后,团队将依赖API来构建应用程序的其余部分。
在设计API时,您需要牢记用户及其目标。API应该从消费者的角度进行设计。API的使用者可以是与您的应用程序交互的用户,也可以是调用您的API的另一个应用程序。
确定API的目标
在本段中,我将解释API目标画布方法。Arnaud Lauret在《Web API的设计》一书中提到了这种方法。
要确定API的目标,您需要确定它的用户可以通过使用它实现什么。首先要识别API的用户。之后,您尝试列出用户可以做什么。然后,确定用户是如何做到这一点的。在这个过程中,您将找到用户实现这一目标所需的输入。
这是一个迭代过程,它看起来像这样:
例如,让我们回答以下问题。在这种情况下,API用户是在电子商务平台上管理产品目录的卖家或管理员。
- 用户是谁?
- 他们能做什么?
- 他们是怎么做到的?
- 他们需要做什么?
- 他们得到了什么回报?
- 输入来自哪里?
- 如何使用输出?
通过回答上述问题,您可以得出API目标画布:
与DDD和API目标画布一起,您可以获得域的完整图片。您还可以识别微服务及其通过API公开的功能。下一步是设计API并开始记录它们。
设计和记录API
一旦确定了API的目标,就可以开始设计和记录API了。设计和实现公共API的事实标准是RESTfulAPI。
什么是RESTFul API?
RESTful API是一种符合REST体系结构风格约束并允许与RESTful web服务交互的API。REST表示表示状态转移,它是一个架构约束。
REST将应用程序视为web资源网络。这些web资源可以通过URI访问,例如http://www.example.com/products/1234. 用户可以对资源执行操作,如GET或POST,以转换状态(应用程序状态转换)。
关于REST的一个常见误解是,它的API协议是通过HTTP实现的JSON。REST不是协议。您可以通过多种方式实现REST。但是,到目前为止,实现REStFul API最流行的方法是HTTP协议之上的JSON负载。
HTTP方法
HTTP资源表示为名词。例如,/products
和/orders
表示产品和订单资源(也称为集合)。您可以使用HTTP方法(也称为动词)对资源执行一些操作。
最常用的HTTP方法有:
- POST:根据提供的数据创建新对象。例如,
POST/products
创建一个新产品。 - GET:返回对象。例如,
GET/products/1234
返回由ID1234标识的产品。 - DELETE:删除对象。例如,
DELETE/products/1234
删除id 1234标识的产品。 - PUT:替换对象或创建新对象。例如,如果产品不存在或替换对象,则
PUT/products
将创建新产品。 - PATCH:对对象应用部分更新。
除此之外,还有其他HTTP方法,例如HEAD、OPTIONs。您可以在HTTP1.1规范中看到方法的详细信息。
使用OpenAPI规范记录RESTFul API
OpenAPI规范提供了定义和记录API的标准。
OpenAPI规范(OAS)为HTTP API定义了一个标准的、与编程语言无关的接口描述,它允许人类和计算机发现和理解服务的功能,而无需访问源代码、附加文档或检查网络流量。通过OpenAPI正确定义后,使用者可以用最少的实现逻辑理解远程服务并与之交互。
OpenAPI规范
用于记录OpenAPI规范的工具
通常,OpenAPI以YAML或JSON格式记录。因此,您需要一个工具,因为编写YAML/JSON规范并不容易。有许多工具可用于记录和设计API。其中一些工具是:
- Swagger UI
- OpenAPI GUI
- Postman
- apiary
其中一些工具还具有在API设计期间进行协作的功能。例如,SwaggerHub允许您创建API并与您的团队共享以供审阅。
您可以在GitHub repo(https://github.com/techdozo/microservices/blob/master/product-catalog-svc/openApi.yaml)中看到产品目录服务的OpenAPI规范。在较高级别上,Swagger editor中产品目录的OpenAPI规范如下所示:
微服务的组织代码
您需要解决的问题之一是如何组织微服务的代码。通常,有两种可能的方法来组织微服务的代码。
1. 单一回购
在这种方法中,您将所有微服务放在一个存储库中。对于Maven,您可以使用Maven多模块方法来组织微服务的代码。类似地,对于Gradle,可以使用多项目构建。这种方法的好处是所有代码都组织在一个地方。这种方法的缺点是您需要高级的DevOps实践和工具。当代码库非常大时尤其如此。
2. 每个微服务的单一回购
在这种方法中,每个微服务都有自己的存储库。这是一个简单得多的方法。在monorepo
方法中,由于所有代码都在一个地方,您可能会意外地在微服务之间引入耦合。但是,这与“每个微服务的单一回购”方法无关。同样,这种方法的最大缺点是,升级Spring Boot依赖关系需要对所有具有多个提交的repo执行,这一点非常简单。
在Spring Boot中创建微服务
在SpringBoot中创建微服务的最简单方法是在SpringInitializer中定义项目。
您需要了解的一些重要配置包括:
- Build:选择Gradle或Maven。它在一个可部署的jar中构建了一个Spring引导应用程序。
- SpringWeb:用于RESTfulWebAPI。默认情况下,它添加嵌入式ApacheTomcat作为依赖项。
- Lombok:使用Lombok停止编写biolerplate getter和setter。
- SpringDataJPA:在JPA之上提供方便的API。
- H2数据库:内存占用率低的内存中数据库。对于prod,您应该使用一些真实的数据库。
配置完SpringBoot项目后,通过选择“Generate”下载zip。最后,在IDE中提取zip并导入项目。
使用六边形体系结构实现微服务
六边形体系结构允许您分离关注点。简而言之,它表示应用程序和域层包含核心业务逻辑。因此,它不应该依赖于数据库和消息传递等基础设施问题。您可以自由更改技术选择,同时保持业务逻辑不变。
六边形体系结构也称为端口和适配器。该体系结构在应用程序/域层中定义端口(接口),并在不同层中提供实现。因此,应用层完全不知道实现。例如,这允许您在不更改业务逻辑的情况下更改数据库。
例如,您可以在域层中定义存储库接口ProductCatalogRepository
。这个接口的实现可以在持久层中完成。总而言之,域层代码只知道接口,而不知道实现。
在六边形体系结构中,您可以按每个包的方式分层组织代码,如下所示:
实现API
在Spring Boot中实现微服务的第一步是实现控制器。控制器提供了一个API的实现。要实现控制器,需要使用@RestController
注释定义一个类。要实现API,您需要定义带有适当注释的方法。例如,PostAPI的@PostMapping
等等。
您可以将POST/products
API实现为:
@PostMapping("/products") //1
public ResponseEntity<ProductResponse> createProduct(
@RequestHeader("sellerId") String sellerId, //2
@Valid @RequestBody ProductRequest productRequest) {
var product = ProductRequestMapper.MAPPER.map(productRequest); //3
var productCatalogCommand = productCatalogFactory.getProductCatalogCommand();
var productId = productCatalogCommand.addProduct(product);
var productResponse = new ProductResponse(productId);
return new ResponseEntity<>(productResponse, HttpStatus.CREATED);
}
让我们了解这里正在做什么-
1. 注释@PostMapping(“/products”)
指其API POST/products
的实现。
2. 强制请求标头sellerId被映射到变量sellerId作为@RequestHeader(“sellerId”)
。
3. 为了保持关注点的分离,我们将API请求对象CreateProductRequest
映射到域对象产品。这里我们使用了MapStruct
,它提供了简单的基于注释的代码来定义映射。
4. 命令负责实施应用程序工作流。我们通过调用工厂作为productCatalogFactory.getProductCatalogCommand()
来获取productCatalogCommand
。
5. 然后我们调用命令将产品添加到产品目录中,作为productCatalogCommand.addProduct(product)
。
6. 获得productId
后,我们将响应作为new ResponseEntity<>(productResponse,HttpStatus.CREATED)
返回。这里,HttpStatus.CREATED
表示HTTP状态代码201。
代码示例
您可以在GitHub上找到本文中提到的示例的源代码(https://github.com/techdozo/microservices/tree/master/product-catalog-svc)。
示例代码包含:
- API实现。
- SpringDataJPA存储库的实现。
- 基本的错误处理。
- 聚合根产品目录实现。
Postman测试
您可以从IDE本地运行产品目录Spring Boot应用程序。然后要在Postman中测试API,请导入OpenAPI规范并将变量baseUrl定义为localhost:8080
。
在Postman中,您可以从响应中定义动态变量。这有助于您测试从响应接收到的值。例如,您可以从响应中读取productId,并在测试部分将其设置为集合变量,如下所示:
const jsonResponse = pm.response.json();
pm.collectionVariables.set("productId", jsonResponse.productId);
您可以从GitHub repo(https://github.com/techdozo/microservices/blob/master/product-catalog-svc/collections/Product%20catalog%20service.postman_collection.json)导入集合。这包含预定义的邮递员变量。
总结
在本文中,我们介绍了一些基本情况。我们理解——
- 微服务是围绕业务能力构建的。
- 领域驱动设计是一种设计微服务体系结构的技术。
- Event storming是DDD的轻量级框架。
- API优先方法要求API的设计和开发先于实现。
- 在设计API时,您需要牢记用户及其目标。API目标画布是确定用户API目标的一种实用方法。
- Spring Boot使实现微服务变得超级简单。
原文地址:https://techdozo.dev/restful-microservices-with-spring-boot-and-kubernetes/
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/2455.html
暂无评论