java|Java 中的超快微服务( 当Microstream遇上Open Liberty)

当我们谈论创建可扩展的应用程序时,微服务已经成为一个流行语。但这还不足够,与任何软件架构决策一样,它有一个权衡和几个挑战。幸运的是,对于我们Java开发人员来说,有两种工具的组合使我们的生活更轻松:Microstream和MicroProfile。本文将介绍如何将Microstream和 Open Liberty 结合起来,以创建一个轻松稳定且超快速的微服务应用程序。
java|Java 中的超快微服务( 当Microstream遇上Open Liberty)
文章图片

具有Open Liberty的微服务
微服务给我们软件工程师带来了一些挑战,特别是作为面对分布式系统的第一步。但这并不意味着我们是孤独的。事实上,有几种工具可以让我们在Java世界中的生活更轻松,尤其是MicroProfile。
MicroProfile的目标是针对微服务架构优化企业版 Java 。它基于Java EE / Jakarta EE标准以及专门用于微服务的API,如Rest Client,Configuration,Open API等。
Open Liberty就是这些实现之一,它以IBM为主要贡献者。Open Liberty 是一个轻量级的开放式框架,用于构建快速高效的云原生 Java 微服务。它为运行云原生应用和微服务提供了足够的运行时。
Microstream的数据持久性非常快
一旦我们谈论微服务,我们就会谈论分布式系统及其挑战,这种谈论在持久性层中将是相同的。
当你有更多关于业务的不确定信息时,我们应该有一个模型,甚至是无模式数据库。尽管如此,持久性层仍然存在很多问题,主要是因为它很难改变。
制作可扩展应用程序的秘诀之一是确保它是无状态的,但我们在持久性层中负担不起它。首先,数据库旨在保留信息及其状态。
使数据持久化层更自然的解决方案之一是直接与 Java 实体作为图形集成。这就是Microstream所做的。
Microstream通过纯Java实现超快的在内存中处理数据。它提供微秒级查询时间、低延迟数据访问、巨大的数据吞吐量和工作负载。因此,它节省了数据中心的大量CPU功耗,二氧化碳排放和成本。
显示代码
让我们将两者结合起来,打造一个超快的微服务。一旦主要目标是展示两者如何结合,我们将选择一个流畅的演示。在此示例中,我们将创建一个简单的 CRUD,其中包含产品、名称和评级,并将其导出为 Rest API。
第一步是创建MicroProfile骨架:它毫不费力且流畅,主要是因为我们可以使用MicroProfile启动器进行可视化配置。配置文件版本 4.1 、 Java 11 和 Open Liberty ,如下图所示
java|Java 中的超快微服务( 当Microstream遇上Open Liberty)
文章图片

现在有了应用程序的骨架。下一步就是添加Microstream并使两者协同工作。幸运的是,有一个库可以通过CDI扩展集成两者。因此,任何具有CDI和MicroProfile Config的应用程序都可以借助此API工作。
请查看最新版本并将其添加到您的应用程序中。

1. 2. one.microstream 3. microstream-integrations-cdi 4. LAST_VERSION_HERE 5.

骨架已设置,因此让我们从代码开始。模型是中心部分。一旦它是一个平滑的示例,我们将创建一个包含几个字段的产品实体。使用Microstream的主要建议是使用不可变实体。因此,我们将创建一个产品作为不可变的实体。
1.public class Product { 2.private final long id; 3.private final String name; 4.private final String description; 5.private final int rating; 6. 7.@JsonbCreator 8.public Product( 9.@JsonbProperty("id") final long id, 10.@JsonbProperty("name") final String name, 11.@JsonbProperty("description") final String description, 12.@JsonbProperty("rating") final int rating 13.) { 14.this.id = id; 15.this.name = name; 16.this.description = description; 17.this.rating = rating; 18.}

JSON 注释仅告知 MicroProfile 如何将实体序列化为 JSON。
下一步是定义产品集合,我们称之为“库存”。库存类是一组具有多种操作方法的产品。
此类是实体与Microstream引擎之间的链接。与Microstream的连接是使用注释Storage 。
1.import java.util.Collections; 2.import java.util.HashSet; 3.import java.util.Objects; 4.import java.util.Optional; 5.import java.util.Set; 6.import java.util.function.Predicate; 7. 8.import one.microstream.integrations.cdi.types.Storage; 9. 10. 11.@Storage 12.public class Inventory { 13.private final Set products = new HashSet<>(); 14. 15.public void add(final Product product) { 16.Objects.requireNonNull(product, "product is required"); 17.this.products.add(product); 18.} 19. 20.public Set getProducts() { 21.return Collections.unmodifiableSet(this.products); 22.} 23. 24.public Optional findById(final long id) { 25.return this.products.stream().filter(this.isIdEquals(id)).limit(1).findFirst(); 26.} 27. 28.public void deleteById(final long id) { 29.this.products.removeIf(this.isIdEquals(id)); 30. 31.} 32. 33.private Predicate isIdEquals(final long id) { 34.return p -> p.getId() == id; 35.} 36. 37.@Override 38.public boolean equals(Object o) { 39.if (this == o) return true; 40.if (o == null || getClass() != o.getClass()) return false; 41.Inventory inventory = (Inventory) o; 42.return Objects.equals(products, inventory.products); 43.} 44. 45.@Override 46.public int hashCode() { 47.return Objects.hash(products); 48.} 49. 50.@Override 51.public String toString() { 52.return "Inventory{" + 53."products=" + products + 54.'}'; 55.} }

集合准备就绪后,让我们创建存储库。要使用我们的类,我们可以使用 CDI 中的注释。我们需要将此操作提交到将要更改此集合的每个操作中。对于任何更改库存的方法,都有一个InventoryInjectStore注释为我们自动处理它。
1.public interface ProductRepository 2.{ 3.Collection getAll(); 4. 5.Product save(Product item); 6. 7.Optional findById(long id); 8. 9.void deleteById(long id); 10.} 11. 12. 13.@ApplicationScoped 14.public class ProductRepositoryStorage implements ProductRepository { 15.private static final Logger LOGGER = Logger.getLogger(ProductRepositoryStorage.class.getName()); 16. 17.@Inject 18.private Inventory inventory; 19. 20.@Override 21.public Collection getAll() { 22.return this.inventory.getProducts(); 23.} 24. 25.@Override 26.@Store 27.public Product save(final Product item) { 28.this.inventory.add(item); 29.return item; 30.} 31. 32.@Override 33.public Optional findById(final long id) { 34.LOGGER.info("Finding the item by id: " + id); 35.return this.inventory.findById(id); 36.} 37. 38.@Override 39.@Store 40.public void deleteById(final long id) { 41.this.inventory.deleteById(id); 42.} }

最后一步是将此产品公开为 Rest API。然后,我们将使用Jakarta EE API返回MicroProfile:JAX-RS。接下来,我们将使用 MicroProfile 创建 Open API 文档。
1.@RequestScoped 2.@Path("products") 3.@Consumes(MediaType.APPLICATION_JSON) 4.@Produces(MediaType.APPLICATION_JSON) 5.public class ProductController 6.{ 7.@Inject 8.private ProductRepository repository; 9. 10.// TODO don't worried about pagination 11.@GET 12.@Operation(summary = "Get all products", description = "Returns all available items at the restaurant") 13.@APIResponse(responseCode = "500", description = "Server unavailable") 14.@APIResponse(responseCode = "200", description = "The products") 15.@Tag(name = "BETA", description = "This API is currently in beta state") 16.@APIResponse(description = "The products", responseCode = "200", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Collection.class, readOnly = true, description = "the products", required = true, name = "products"))) 17.public Collection getAll() 18.{ 19.return this.repository.getAll(); 20.} 21. 22.@GET 23.@Path("{id}") 24.@Operation(summary = "Find a product by id", description = "Find a product by id") 25.@APIResponse(responseCode = "200", description = "The product") 26.@APIResponse(responseCode = "404", description = "When the id does not exist") 27.@APIResponse(responseCode = "500", description = "Server unavailable") 28.@Tag(name = "BETA", description = "This API is currently in beta state") 29.@APIResponse(description = "The product", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Product.class))) 30.public Product findById( 31.@Parameter(description = "The item ID", required = true, example = "1", schema = @Schema(type = SchemaType.INTEGER)) @PathParam("id") final long id) 32.{ 33.return this.repository.findById(id).orElseThrow( 34.() -> new WebApplicationException("There is no product with the id " + id, Response.Status.NOT_FOUND)); 35.} 36. 37.@POST 38.@Operation(summary = "Insert a product", description = "Insert a product") 39.@APIResponse(responseCode = "201", description = "When creates an product") 40.@APIResponse(responseCode = "500", description = "Server unavailable") 41.@Tag(name = "BETA", description = "This API is currently in beta state") 42.public Response insert( 43.@RequestBody(description = "Create a new product.", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Product.class))) final Product product) 44.{ 45.return Response.status(Response.Status.CREATED).entity(this.repository.save(product)).build(); 46.} 47. 48.@DELETE 49.@Path("{id}") 50.@Operation(summary = "Delete a product by ID", description = "Delete a product by ID") 51.@APIResponse(responseCode = "200", description = "When deletes the product") 52.@APIResponse(responseCode = "500", description = "Server unavailable") 53.@Tag(name = "BETA", description = "This API is currently in beta state") 54.public Response delete( 55.@Parameter(description = "The item ID", required = true, example = "1", schema = @Schema(type = SchemaType.INTEGER)) @PathParam("id") final long id) 56.{ 57.this.repository.deleteById(id); 58.return Response.status(Response.Status.NO_CONTENT).build(); 59.} 60. }

就是这样,我们可以测试正在运行的应用程序并检查结果。
1.mvn clean package 2.java -jar target/openliberty-example.jar 3. 4.curl --location --request POST 'http://localhost:8080/products/' \ 5.--header 'Content-Type: application/json' \ 6.--data-raw '{"id": 1, "name": "banana", "description": "a fruit", "rating": 5}' 7. 8.curl --location --request POST 'http://localhost:8080/products/' \ 9.--header 'Content-Type: application/json' \ 10.--data-raw '{"id": 2, "name": "watermelon", "description": "watermelon sugar ahh", "rating": 4}' 11. 12.curl --location --request GET 'http://localhost:8080/products/' 13. curl --location --request GET 'http://localhost:8080/products/1'

我们终于在Open Liberty和Microstream之间实现了集成。本教程展示了两者如何协同工作,并为您提供了一个面对持久性问题的新工具:Microstream。事实上,当你想要创建微服务来超快速运行它时,Microstream和Open Liberty就是伟大的盟友。
【java|Java 中的超快微服务( 当Microstream遇上Open Liberty)】

    推荐阅读