有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在微服务之间最好地共享和存储类似枚举的数据?

情况: 具有以下功能的微服务体系结构:

  • 微服务是用Java编写的,带有Spring引导和Hibernate
  • 一种选项服务,通过REST接口提供有关选项的信息
  • 选项可按如下方式建模的数据,例如通过枚举(代表性)
    • 具有一些与之关联的属性,如enabledstatus。将来不太可能添加更多属于选项的属性,这些属性必须与之直接关联
    • 必须很少添加新的选项s和选项类型s。它们将永远不会被删除(如果需要,只需禁用)
    • 选项应具有可引用的唯一标识符
    • 如果可能的话,不应该有未知选项
enum OptionType {
   TYPE_A,
   TYPE_B,
   TYPE_C;
}

enum Option {
    TYPE_A_X1(TYPE_A),
    TYPE_A_X2(TYPE_A),

    TYPE_B_Z1(TYPE_B, false),
    TYPE_B_Z2(TYPE_B);

    TYPE_C_U1(TYPE_C);
    TYPE_C_U2(TYPE_C);
    TYPE_C_U3(TYPE_C);

    private final OptionType type;
    private final boolean enabled;

    Option(OptionType type){
        this.type = type;
        this.enabled = true;
    }

    Option(OptionType type, boolean enabled){
        this.type = type;
        this.enabled = enabled;
    }
}

  • 其他微服务(目前为3)需要能够访问选项数据。他们需要知道哪个选项存在,并以某种方式引用选项,例如通过其名称或标识符
    • 其中一个服务(示例服务)需要在自己的REST接口中向外界提供选项数据类型作为过滤器设置。JSON中的filter对象如下所示:
{
  "typeA": "TYPE_A_X1",
  "typeB": "TYPE_B_Z2",
  "typeC": [ "TYPE_C_U1", "TYPE_C_U2"]
  // more filter settings
}

在我看来,在微服务之间存储和共享此选项数据的不同方法:

  • 选项服务选项数据存储在自己的数据库中。如果我将数据从数据库读取到Hibernate实体中,选项从那以后,在任何地方都只是一个String

    • 赞成者:
      • 易于重命名、添加和删除选项s
    • 反对:
      • 在代码中使用选项时没有类型安全性,例如反序列化包含选项的响应时
      • 示例服务无法在其OpenAPI文档中轻松提供选项数据(仅String
      • 微服务需要查询和缓存来自选项服务选项数据
  • 选项数据仅存在于enum中的源代码中,如上面建模的,并通过lib在不同服务之间共享

    • 赞成者:
      • 在需要选项的地方键入安全。在反序列化包含Options数据的响应时非常有用,但也可用于生成OpenAPI文档
      • 微服务仍然可以通过其名称引用其数据库中的选项,因为它是唯一的
    • 反对:
      • 编辑选项的名称很困难
      • 无法删除选项
      • 如果添加了一个新的选项/OptionType,依赖该库的服务更新其库版本的顺序很重要。因为我们无法将响应反序列化为未知选项类型
  • 还有一种可能是混合使用数据库和枚举解决方案,这有一个很大的缺点,即必须同时维护两个真实来源

在微服务之间存储和共享选项数据的最佳方式是什么?什么是最佳实践


共 (3) 个答案

  1. # 1 楼答案

    另一个选项:使用第一个选项,但要有专门的课程

    • 这考虑到了类型安全性
    • 但不要求在编译时知道枚举
    • 不过,如果需要检查Option实例的有效性,则需要一个缓存了允许的Option列表的服务

    示例代码:

    import com.fasterxml.jackson.annotation.JsonValue;
    
    public class Option {
        @JsonValue
        private String value;
            
        Option(String value) {
            this.value = value;
        }
    }
    
  2. # 2 楼答案

    虽然枚举在大多数编程语言中非常有用,但它们可能会成为服务间通信的噩梦。 如果在微服务端点中使用枚举,它将成为API规范的一部分。在一侧更改它们将导致在另一侧出现序列化/反序列化问题。 因此,只有在以下情况下,才应该在API中使用枚举:

    • 你肯定他们不会改变(例如工作日)或
    • 您是所有参与服务的代码的所有者,能够组织一次大爆炸式的重新部署

    在这些情况下,您可以在服务之间创建一个共享库

    如果不适用,让您的生活更轻松,并将大多数EnUM类数据(例如货币代码、国家代码)视为可更改的简单字符串值。如果您想对这些价值进行集中管理,为什么不为其创建一个充当主服务器的微服务呢?这就是微服务架构的用途。提供其他服务可以不时查询的一些端点。你甚至不需要一个持久层

  3. # 3 楼答案

    第一种选择:

    定义或创建新的模块/微服务/项目,该模块/微服务/项目仅包含CommonMessage、String Message、Enum、Exception或所有通用的、可用于使用spring boot的多个微服务的可重用的内容

    但这些枚举没有参数化,因此无法创建更新或删除

    您可以创建用于多种用途的选项ENUM类,并且可以从POM注入这些类。xml作为一种依赖关系

    第二种选择: 将其作为实体对象存储在数据库中,以便管理这些数据。 如果你想在其他微服务上使用这些数据,别忘了在POM中使用这个工件作为依赖项。xml,以便其他微服务可以调用您的服务或存储库