云原生事件和 Spring - 第一部分

工程 | Oleg Zhurakousky | 2020年12月10日 | ...

前言

跨系统和平台的数据一致性云原生事件规范 的一项崇高目标。随着其采用率的不断提高,开发人员和架构师将不再需要担心如何处理来自不同系统和平台的各种事件……但这篇文章的目的并非重新讨论或证明云原生事件的合理性。简单的 Google 搜索就能提供很多论点供您阅读,以帮助解答“为什么选择云原生事件?”这个问题。本篇文章以及后续关于此主题的文章的目标是分享一些想法,以及我们在 Spring 中为应对和处理云原生事件的更广泛采用而进行的工作。

介绍

Message,它是 Spring 对 EIP Message 的实现,是表示云原生事件的足够结构! 我们正在构建的就是这种情况。如果是这样,那么当前依赖于 Spring Messaging 的任何框架或应用程序都将自动支持云原生事件用例。所以……

消息即云原生事件

根据官方网站云原生事件是“一种以通用方式描述事件数据的规范”。

如果您阅读规范(非常简单),您会很快意识到云原生事件有效地定义了一个规范的、与平台无关的数据结构,以便以统一的方式跨系统和平台交换。该结构相当简单。它将一些有效负载封装为data字段,并将其他元数据封装为attributes(键/值结构)。attributes本身又分为明确定义的元数据字段,称为attributes(必需和可选),以及松散定义或未定义的字段,称为扩展属性

目前就这些。

现在,对于那些熟悉Message(核心企业集成模式之一)及其在Spring Messaging中的定义的人来说,您可能会说:这看起来非常熟悉!而且确实如此。

与云原生事件一样,Message 定义了一个规范的、与平台无关的数据结构,以便以统一的方式跨系统和平台交换。此结构非常简单。它将一些有效负载封装为payload字段,并将元数据封装为headers(键/值结构)。

为什么这很重要?与任何其他技术一样,在 Spring 中提供对云原生事件的集成实际上是实现其概念在众所周知且熟悉的(对于其用户而言)Spring 习惯用法和抽象之内的努力问题。Message 因此浮现在脑海中。鉴于其与云原生事件规范定义的结构几乎完美匹配,“Message 可以作为 Spring 中表示云原生事件的适当抽象吗?”因为,如果答案是“是”,那么当前依赖于 Spring Messaging 的数万个框架和应用程序可以自动支持云原生事件用例,这意味着此类框架的用户以及框架本身都能够识别传入的云原生事件实例以及创建它们,所有这些都在规范定义的协议细节范围内,例如属性前缀类型系统等等。

功能性与非功能性(样板代码)

我们还需要了解一些典型的云原生事件使用模式。我们这样做是为了隔离我们所谓的功能性非功能性(样板代码)方面。因此,让我们描述其中一些方面。

  • 生成一些内容并将其封装到云原生事件中
  • 使用可能源自云原生事件的内容
  • 使用实际的云原生事件(与上面不同,因为它意味着使用整个事件)
  • 基于云原生事件属性进行路由和过滤

此列表只是一些典型使用模式的小子集,但它有助于说明问题领域。它还有助于我们开始理解和隔离功能性非功能性方面。同样有趣的是,大多数描述的模式是非功能性方面的示例,这是经验丰富的 Spring 用户期望框架处理的内容。例如,虽然用户预期“生成一些内容”(功能性),但“将其封装到云原生事件中”部分应由框架处理(非功能性)。同样的原则也适用于使用云原生事件。虽然表达含糊,但它通常意味着用户可能只关心云原生事件的数据部分,很可能期望它以框架应该提取、转换和服务的特定于领域的物体的形式出现。所有这些再次是非功能性方面的示例。然后是云原生事件属性及其前缀(例如,ce_ce- 等)的问题,它们有效地描述了事件的来源或目的地,人们会期望框架也处理这些问题,尤其是在功能的实现者甚至可能不知道事件的来源或目的地的情况下。

Spring

Spring 通过基于消息的框架成功地支持转换、类型转换、路由、过滤和许多其他消息传递模式(其中大多数由企业集成模式 描述)已有十多年,并且数万个用户应用程序在生产环境中运行。我们怎么能忘记基础设施类型的问题,例如连接性、会话和事务管理、发送和接收、重试、错误处理、恢复等等?在 Spring 中,我们的座右铭是我们尝试处理非功能性(样板代码)问题,只留下功能性(业务逻辑)问题。因此,在给定集成的上下文中区分两者并尽可能多地外包给框架始终非常重要。我们还公开了实用程序、库和配置选项,让您可以影响某些非功能性问题,因为出于各种原因,这样做仍然可能是必需的。

那么,鉴于这一点,支持云原生事件的典型 Spring 应用程序会是什么样子,尤其是在Spring Boot 时代?

这是一个应用程序的示例,它接收 HTTP 请求作为云原生事件,并生成 HTTP 响应作为云原生事件。

@SpringBootApplication
public static class SampleApplication
  public static void main(String[] args) throws Exception {
    SpringApplication.run(SampleApplication.class, args);
  }

  @Bean
  Function<Person, Employee> hire() {
	return person -> {
            Employee employee = ...
            return employee;
        };
  }
}

这是一个应用程序的示例,它从 Apache Kafka 接收云原生事件并将其发送到 RabbitMQ 消息代理。

@SpringBootApplication
public static class SampleApplication
  public static void main(String[] args) throws Exception {
    SpringApplication.run(SampleApplication.class, args);
  }

  @Bean
  Function<Person, Employee> hire() {
	return person -> {
            Employee employee = ...
            return employee;
        };
  }
}

我们省略了函数的实现细节,因为它们与主题无关。框架并不真正关心您做什么。它只关心您期望什么——输入——以及您生成什么——输出——而该信息可从函数签名中获得。

但是,我确信这不是您考虑的问题,因为您可能想知道为什么我作为不同的两个应用程序实际上是相同的?哪里说明一个应用程序是 REST 端点,而另一个是消息处理程序?好吧,要回答这些问题,我们需要知道执行的上下文,该上下文来自 Spring Boot 自动配置,这些配置可用于您的应用程序类路径。例如,为了使第一个应用程序的描述正确,您需要在类路径中包含spring-cloud-function-web依赖项,这将带来所有必要的组件和将您的函数公开为 REST 端点所需的附加自动配置。至于第二个,我们可以简单地回退到我们已经为 Apache Kafka、AMQP、Solace、HTTP、AWS、Google 等提供的广泛的绑定程序库。这些绑定程序和相关的自动配置将使示例代码成为消息处理程序。

消息

消息是此启用功能的核心,它是Spring中所有活动部件都理解的唯一规范结构。它是一个能够清晰地传达意图和期望的结构。它来自哪里?它将去哪里?谁发送的?内容是什么?它是否代表一个云事件?如果是,它是二进制模式还是结构化模式? 清单永无止境,但唯一不变的是,消息作为一种结构和概念,能够很好地回答这些问题。考虑到这一点,云事件就变成了另一种消息。Spring框架可以像处理任何其他消息一样处理它,让您可以专注于业务逻辑,而不是底层实现的细节。

摘要

因此,消息不仅是表示云事件的足够结构,也是在Spring中处理云事件用例的正确抽象。我希望这一点很清楚,随着即将推出的对消息的云事件支持,我们正在为任何依赖于Spring Messaging的应用程序提供云事件支持的道路上。

后续文章中,我们将介绍即将在多个Spring框架中推出的云事件支持的技术细节,以及使用Cloud Event Java SDK与Spring集成云事件的方法。您现在也可以开始查看一些示例。

获取Spring新闻

关注Spring新闻

订阅

领先一步

VMware提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring在一个简单的订阅中提供OpenJDK™、Spring和Apache Tomcat®的支持和二进制文件。

了解更多

即将举行的活动

查看Spring社区中所有即将举行的活动。

查看全部