Overview of Spring Integration Framework
Spring Integration 提供了 Spring 编程模型的扩展来支持众所周知的 { Enterprise Integration Patterns}。它启用了基于 Spring 的应用程序内的轻量级消息传递,并通过声明性适配器支持与外部系统的集成。这些适配器提供了比 Spring 对远程操作、消息传递和调度的支持更高级别的抽象。
Spring Integration provides an extension of the Spring programming model to support the well known Enterprise Integration Patterns. It enables lightweight messaging within Spring-based applications and supports integration with external systems through declarative adapters. Those adapters provide a higher level of abstraction over Spring’s support for remoting, messaging, and scheduling.
Spring Integration 的主要目标是提供一个简单的模型,用于构建企业集成解决方案,同时保持关注点分离,这对于生成可维护、可测试的代码至关重要。
Spring Integration’s primary goal is to provide a simple model for building enterprise integration solutions while maintaining the separation of concerns that is essential for producing maintainable, testable code.
Spring Integration Overview
本章提供了对 Spring Integration 核心概念和组件的高级介绍。它包括一些编程技巧,以帮助您充分利用 Spring Integration。
This chapter provides a high-level introduction to Spring Integration’s core concepts and components. It includes some programming tips to help you make the most of Spring Integration.
Background
Spring 框架的一个关键主题是控制反转 (IoC)。从广义上讲,这意味着框架代表其上下文中管理的组件处理职责。组件本身被简化了,因为它们免除了那些职责。例如,依赖项注入减轻了组件查找或创建其依赖项的职责。同样地,面向方面的编程通过将通用横切关注点模块化为可重用方面,将业务组件从关注点中解放出来。在每种情况下,最终结果都是一个更容易测试、理解、维护和扩展的系统。
One of the key themes of the Spring Framework is Inversion of Control (IoC). In its broadest sense, this means that the framework handles responsibilities on behalf of the components that are managed within its context. The components themselves are simplified, because they are relieved of those responsibilities. For example, dependency injection relieves the components of the responsibility of locating or creating their dependencies. Likewise, aspect-oriented programming relieves business components of generic cross-cutting concerns by modularizing them into reusable aspects. In each case, the end result is a system that is easier to test, understand, maintain, and extend.
此外,Spring 框架和产品组合为构建企业应用程序提供了一个全面的编程模型。开发人员可以从该模型的一致性中受益,尤其是从它基于公认的最佳实践(例如面向接口编程、相较于继承更倾向于组合)这一事实中受益。Spring 简化的抽象和强大的支持库提高了开发人员的生产力,同时提高了测试和移植级别。
Furthermore, the Spring framework and portfolio provide a comprehensive programming model for building enterprise applications. Developers benefit from the consistency of this model and especially from the fact that it is based upon well established best practices, such as programming to interfaces and favoring composition over inheritance. Spring’s simplified abstractions and powerful support libraries boost developer productivity while simultaneously increasing the level of testability and portability.
Spring Integration 受这些相同目标和原则的推动。它将 Spring 编程模型扩展到消息传递域,并在 Spring 现有的企业集成支持的基础上构建,以提供更高水平的抽象。它支持消息驱动的架构,其中控制反转适用于运行时问题,例如何时应运行某些业务逻辑以及应发送响应的位置。它支持消息路由和转换,以便集成不同的传输和不同数据格式,而不会影响可测试性。换句话说,消息传递和集成问题由框架处理。业务组件进一步与基础设施隔离,开发人员不再承担复杂的集成职责。
Spring Integration is motivated by these same goals and principles. It extends the Spring programming model into the messaging domain and builds upon Spring’s existing enterprise integration support to provide an even higher level of abstraction. It supports message-driven architectures where inversion of control applies to runtime concerns, such as when certain business logic should run and where the response should be sent. It supports routing and transformation of messages so that different transports and different data formats can be integrated without impacting testability. In other words, the messaging and integration concerns are handled by the framework. Business components are further isolated from the infrastructure, and developers are relieved of complex integration responsibilities.
Spring Integration 是 Spring 编程模型的延伸,它提供了广泛的配置选项,其中包括注解、支持名称空间的 XML、带有通用 “bean” 元素的 XML 以及直接使用基础 API。该 API 基于明确策略接口和非侵入式委派适配器。Spring Integration 的设计灵感来自于对 Spring 中常见模式与 link:https://www.enterpriseintegrationpatterns.com/[Enterprise Integration Patterns 中描述的 Gregor Hohpe 和 Bobby Woolf(Addison Wesley,2004 年)中著名的模式之间紧密关联性的认识。阅读过本书的开发人员应该能够立即了解 Spring Integration 概念和术语。
As an extension of the Spring programming model, Spring Integration provides a wide variety of configuration options, including annotations, XML with namespace support, XML with generic “bean” elements, and direct usage of the underlying API. That API is based upon well-defined strategy interfaces and non-invasive, delegating adapters. Spring Integration’s design is inspired by the recognition of a strong affinity between common patterns within Spring and the well known patterns described in Enterprise Integration Patterns, by Gregor Hohpe and Bobby Woolf (Addison Wesley, 2004). Developers who have read that book should be immediately comfortable with the Spring Integration concepts and terminology.
Goals and Principles
Spring Integration 受以下目标驱动:
Spring Integration is motivated by the following goals:
-
Provide a simple model for implementing complex enterprise integration solutions.
-
Facilitate asynchronous, message-driven behavior within a Spring-based application.
-
Promote intuitive, incremental adoption for existing Spring users.
Spring Integration 受以下原则指导:
Spring Integration is guided by the following principles:
-
Components should be loosely coupled for modularity and testability.
-
The framework should enforce separation of concerns between business logic and integration logic.
-
Extension points should be abstract in nature (but within well-defined boundaries) to promote reuse and portability.
Main Components
从垂直角度来看,分层架构促进了关注点分离,而基于接口的层间契约促进了松散耦合。Spring 驱动的应用程序通常这样设计,Spring 框架和产品组合为遵循针对企业应用程序整个堆栈的最佳实践提供了坚实的基础。消息驱动的架构添加了水平视角,但这些相同目标仍然相关。正如“分层架构”是一种极其通用和抽象的范例,消息传递系统通常遵循类似抽象的“管道和过滤器”模型。“过滤器”表示任何能够生成或消耗消息的组件,“管道”在过滤器之间传输消息,以便组件本身保持松散耦合。值得注意的是,这两种高级范例并不互斥。支持“管道”的底层消息传递基础设施仍应封装在一个契约定义为接口的层中。同样,“过滤器”本身也应该在逻辑上高于应用程序服务层的层中进行管理,通过接口与这些服务交互,就像 Web 层一样。
From a vertical perspective, a layered architecture facilitates separation of concerns, and interface-based contracts between layers promote loose coupling. Spring-based applications are typically designed this way, and the Spring framework and portfolio provide a strong foundation for following this best practice for the full stack of an enterprise application. Message-driven architectures add a horizontal perspective, yet these same goals are still relevant. Just as “layered architecture” is an extremely generic and abstract paradigm, messaging systems typically follow the similarly abstract “pipes-and-filters” model. The “filters” represent any components capable of producing or consuming messages, and the “pipes” transport the messages between filters so that the components themselves remain loosely-coupled. It is important to note that these two high-level paradigms are not mutually exclusive. The underlying messaging infrastructure that supports the “pipes” should still be encapsulated in a layer whose contracts are defined as interfaces. Likewise, the “filters” themselves should be managed within a layer that is logically above the application’s service layer, interacting with those services through interfaces in much the same way that a web tier would.
Message
在 Spring Integration 中,消息是对任何 Java 对象的通用包装,与框架在处理该对象时使用的元数据结合使用。它由有效负载和标头组成。有效负载可以是任何类型,标头包含一些常用的信息,例如 ID、时间戳、关联 ID 和返回地址。标头还用于将值传递到连接的传输和从传输中传递值。例如,当从收到的文件中创建消息时,文件名可能会存储在标头中,以便下游组件访问。同样,如果消息的内容最终将由 outbound 邮件适配器发送,则不同的属性(收件人、发件人、抄送、主题等)可能会由上游组件配置为消息标头值。开发人员还可以在标头中存储任意键值对。
In Spring Integration, a message is a generic wrapper for any Java object combined with metadata used by the framework while handling that object. It consists of a payload and headers. The payload can be of any type, and the headers hold commonly required information such as ID, timestamp, correlation ID, and return address. Headers are also used for passing values to and from connected transports. For example, when creating a message from a received file, the file name may be stored in a header to be accessed by downstream components. Likewise, if a message’s content is ultimately going to be sent by an outbound mail adapter, the various properties (to, from, cc, subject, and others) may be configured as message header values by an upstream component. Developers can also store any arbitrary key-value pairs in the headers.
Message Channel
消息通道表示管道和过滤器架构的“管道”。生产者将消息发送到通道,消费者从通道接收消息。因此,消息通道解耦了消息传递组件,并且还提供了拦截和监视消息的便捷点。
A message channel represents the “pipe” of a pipes-and-filters architecture. Producers send messages to a channel, and consumers receive messages from a channel. The message channel therefore decouples the messaging components and also provides a convenient point for interception and monitoring of messages.
消息通道可能会遵循点对点或发布-订阅语义。使用点对点通道,每个发送到通道的消息最多只能由一个消费者接收。另一方面,发布-订阅通道尝试向通道上的所有订阅者广播每条消息。Spring Integration 支持这两种模型。
A message channel may follow either point-to-point or publish-subscribe semantics. With a point-to-point channel, no more than one consumer can receive each message sent to the channel. Publish-subscribe channels, on the other hand, attempt to broadcast each message to all subscribers on the channel. Spring Integration supports both of these models.
虽然 “point-to-point” 和“发布-订阅”定义了最终接收每条消息的消费者数量的两个选项,但还有另一个重要考虑:通道是否应该缓冲消息?在 Spring Integration 中,可轮询通道能够在队列中缓冲消息。缓冲的优点是可以节流入站消息,从而防止消费者过载。但是,正如其名称所暗示的,这也增加了一些复杂性,因为消费者只能从这样的通道接收消息,前提是配置了一个轮询器。另一方面,连接到可订阅通道的消费者仅仅是消息驱动的。Message Channel Implementations 详细讨论了 Spring Integration 中可用的各种通道实现。
Whereas “point-to-point” and "publish-subscribe" define the two options for how many consumers ultimately receive each message, there is another important consideration: Should the channel buffer messages? In Spring Integration, pollable channels are capable of buffering Messages within a queue. The advantage of buffering is that it allows for throttling the inbound messages and thereby prevents overloading a consumer. However, as the name suggests, this also adds some complexity, since a consumer can only receive the messages from such a channel if a poller is configured. On the other hand, a consumer connected to a subscribable channel is simply message-driven. Message Channel Implementations has a detailed discussion of the variety of channel implementations available in Spring Integration.
Message Endpoint
Spring Integration 的主要目标之一是通过控制反转来简化企业集成解决方案的开发。这意味着您不必直接实现消费者和生产者,甚至不必在消息通道上构建消息并调用发送或接收操作。相反,您应该能够专注于基于普通对象的实现来您的特定域模型。然后,通过提供声明性配置,您可以将您的域特定代码“连接”到 Spring Integration 提供的消息传递基础设施。负责这些连接的组件是消息端点。这并不意味着您应该直接连接您现有的应用程序代码。任何现实世界的企业集成解决方案都需要一定数量的代码来关注集成问题,例如路由和转换。重要的是在集成逻辑和业务逻辑之间实现关注点分离。换句话说,与 Web 应用程序的模型-视图-控制器 (MVC) 范例一样,目标应该是提供一个薄但专门的层,将入站请求转换为服务层调用,然后将服务层返回值转换为出站回复。下一节概述了处理这些职责的消息端点类型,而在即将到来的章节中,您将了解 Spring Integration 的声明性配置选项如何提供一种非侵入性的方式来使用每个端点。
One of the primary goals of Spring Integration is to simplify the development of enterprise integration solutions through inversion of control. This means that you should not have to implement consumers and producers directly, and you should not even have to build messages and invoke send or receive operations on a message channel. Instead, you should be able to focus on your specific domain model with an implementation based on plain objects. Then, by providing declarative configuration, you can “connect” your domain-specific code to the messaging infrastructure provided by Spring Integration. The components responsible for these connections are message endpoints. This does not mean that you should necessarily connect your existing application code directly. Any real-world enterprise integration solution requires some amount of code focused upon integration concerns such as routing and transformation. The important thing is to achieve separation of concerns between the integration logic and the business logic. In other words, as with the Model-View-Controller (MVC) paradigm for web applications, the goal should be to provide a thin but dedicated layer that translates inbound requests into service layer invocations and then translates service layer return values into outbound replies. The next section provides an overview of the message endpoint types that handle these responsibilities, and, in upcoming chapters, you can see how Spring Integration’s declarative configuration options provide a non-invasive way to use each of these.
Message Endpoints
消息端点表示管道和过滤器架构的 {“filter”}。如前所述,端点的主要角色是将应用程序代码连接到消息传递框架,并以非侵入性的方式进行连接。换句话说,应用程序代码理想情况下应该不了解消息对象或消息通道。这类似于 MVC 范式中控制器的角色。就像控制器处理 HTTP 请求一样,消息端点处理消息。就像控制器映射到 URL 模式一样,消息端点映射到消息通道。两个示例的目标相同:让应用程序代码与基础设施隔离开。这些概念以及所有随后的模式都将在 { Enterprise Integration Patterns} 一书中进行详细讨论。在此,我们仅对 Spring Integration 支持的主要端点类型以及与这些类型关联的角色提供高级别描述。后面的章节会进行详细说明并提供示例代码以及配置示例。
A Message Endpoint represents the “filter” of a pipes-and-filters architecture. As mentioned earlier, the endpoint’s primary role is to connect application code to the messaging framework and to do so in a non-invasive manner. In other words, the application code should ideally have no awareness of the message objects or the message channels. This is similar to the role of a controller in the MVC paradigm. Just as a controller handles HTTP requests, the message endpoint handles messages. Just as controllers are mapped to URL patterns, message endpoints are mapped to message channels. The goal is the same in both cases: isolate application code from the infrastructure. These concepts and all the patterns that follow are discussed at length in the Enterprise Integration Patterns book. Here, we provide only a high-level description of the main endpoint types supported by Spring Integration and the roles associated with those types. The chapters that follow elaborate and provide sample code as well as configuration examples.
Message Transformer
消息转换器负责转换消息的内容或结构并返回经过修改的消息。最常见的一种转换器可能是将消息的有效负载从一种格式转换为另一种格式(例如从 XML 转换为 java.lang.String
)的转换器。同样,转换器可以添加、删除或修改消息的头值。
A message transformer is responsible for converting a message’s content or structure and returning the modified message.
Probably the most common type of transformer is one that converts the payload of the message from one format to another (such as from XML to java.lang.String
).
Similarly, a transformer can add, remove, or modify the message’s header values.
Message Filter
消息过滤器确定是否应将消息传递至输出通道。这只需一个提供布尔值测试方法即可,该方法可检查特定的有效负载内容类型、属性值、头信息的存在或其他条件。如果接受该消息,则将其发送至输出通道。如果没有,则将丢弃该消息(或对于更严格的实现,可能会引发 Exception
)。消息过滤器通常与发布-订阅通道结合使用,其中多个使用者可以接收到相同的消息,并使用过滤器的条件缩小要处理的消息的集合。
A message filter determines whether a message should be passed to an output channel at all.
This simply requires a boolean test method that may check for a particular payload content type, a property value, the presence of a header, or other conditions.
If the message is accepted, it is sent to the output channel.
If not, it is dropped (or, for a more severe implementation, an Exception
could be thrown).
Message filters are often used in conjunction with a publish-subscribe channel, where multiple consumers may receive the same message and use the criteria of the filter to narrow down the set of messages to be processed.
小心不要将 “filter” 在管道和过滤器架构模式中的通用用法与这种特定的端点类型混淆,后者有选择地缩小在两个通道之间流动的消息。“filter” 的管道和过滤器概念与 Spring Integration 的消息端点更匹配:任何可以连接到消息通道以发送或接收消息的组件。 |
Be careful not to confuse the generic use of “filter” within the pipes-and-filters architectural pattern with this specific endpoint type that selectively narrows down the messages flowing between two channels. The pipes-and-filters concept of a “filter” matches more closely with Spring Integration’s message endpoint: any component that can be connected to a message channel in order to send or receive messages. |
Message Router
消息路由器负责确定消息接下来应接收哪个(如果有)通道。通常,此决策基于消息的内容或消息头中的可用元数据。消息路由器通常用作服务激活器或其他能够发送答复消息的端点上静态配置输出通道的动态替代方案。同样,消息路由器提供了对先前描述的多订阅者使用的方法消息过滤器使用的响应式消息过滤器主动的替代方案。
A message router is responsible for deciding what channel or channels (if any) should receive the message next. Typically, the decision is based upon the message’s content or the metadata available in the message headers. A message router is often used as a dynamic alternative to a statically configured output channel on a service activator or other endpoint capable of sending reply messages. Likewise, a message router provides a proactive alternative to the reactive message filters used by multiple subscribers, as described earlier.
Splitter
拆分器是另一种类型的消息端点,其责任是从其输入通道接收一条消息,将该消息拆分为多条消息,并将每条消息发送其输出通道。此操作通常用于将“组合”有效负载对象拆分为包含细分有效负载的消息组。
A splitter is another type of message endpoint whose responsibility is to accept a message from its input channel, split that message into multiple messages, and send each of those to its output channel. This is typically used for dividing a “composite” payload object into a group of messages containing the subdivided payloads.
Aggregator
合并器基本上是拆分器的镜像,是一种接收多条消息并将它们合并为单条消息的消息端点类型。事实上,合并器通常是包含拆分器的管道中的下游使用者。从技术上讲,合并器比拆分器更复杂,因为它需要维护状态(要合并的消息)、在完整的消息组可用时决定以及在必要时超时。此外,在超时的情况下,合并器需要知道是发送部分结果、丢弃部分结果,还是将部分结果发送到单独的通道。Spring Integration 提供了 CorrelationStrategy
、ReleaseStrategy
以及可配置的超时设置、是否在超时后发送部分结果,以及丢弃通道。
Basically a mirror-image of the splitter, the aggregator is a type of message endpoint that receives multiple messages and combines them into a single message.
In fact, aggregators are often downstream consumers in a pipeline that includes a splitter.
Technically, the aggregator is more complex than a splitter, because it is required to maintain state (the messages to be aggregated), to decide when the complete group of messages is available, and to timeout if necessary.
Furthermore, in case of a timeout, the aggregator needs to know whether to send the partial results, discard them, or send them to a separate channel.
Spring Integration provides a CorrelationStrategy
, a ReleaseStrategy
, and configurable settings for timeout, whether
to send partial results upon timeout, and a discard channel.
Service Activator
服务激活器是用于将服务实例连接到消息传递系统的通用端点。必须配置输入消息通道,并且如果要调用的服务方法能返回值,则还可以提供输出消息通道。
A Service Activator is a generic endpoint for connecting a service instance to the messaging system. The input message channel must be configured, and, if the service method to be invoked is capable of returning a value, an output message Channel may also be provided.
输出通道是可选的,因为每条消息还可以提供自己的“返回地址”头。这个相同的规则适用于所有使用者端点。 |
The output channel is optional, since each message may also provide its own 'Return Address' header. This same rule applies for all consumer endpoints. |
服务激活器调用某个服务对象的某个操作来处理请求消息,提取请求消息的有效负载并进行转换(如果方法不期望消息类型参数)。每当服务对象的方法返回一个值时,该返回值同样会被转换为答复消息,如果需要(如果它已不是消息类型)。该答复消息被发送到输出通道。如果尚未配置输出通道,则会将答复发送至消息的“返回地址”中指定的通道(如果可用)。
The service activator invokes an operation on some service object to process the request message, extracting the request message’s payload and converting (if the method does not expect a message-typed parameter). Whenever the service object’s method returns a value, that return value is likewise converted to a reply message if necessary (if it is not already a message type). That reply message is sent to the output channel. If no output channel has been configured, the reply is sent to the channel specified in the message’s “return address”, if available.
请求-答复服务激活器端点将目标对象的函数连接到输入和输出消息通道。
A request-reply service activator endpoint connects a target object’s method to input and output Message Channels.
如前所述,在 Message Channel 中,通道可能是可轮询的或可订阅的。在前面的图表中,这由 “clock” 符号和实线箭头(轮询)和虚线箭头(订阅)描述。 |
As discussed earlier, in Message Channel, channels can be pollable or subscribable. In the preceding diagram, this is depicted by the “clock” symbol and the solid arrow (poll) and the dotted arrow (subscribe). |
Channel Adapter
通道适配器是一个将消息通道连接到其他系统或传送方式的端点。通道适配器可以是入站还是出站的。通常,通道适配器会在消息与从其他系统接收或发送至其他系统的任何对象或资源(文件、HTTP 请求、JMS 消息等)之间进行一些映射。根据传送方式的不同,通道适配器也可以填充或提取消息头值。Spring Integration 提供了大量通道适配器,这些通道适配器在后续章节中有所说明。
A channel adapter is an endpoint that connects a message channel to some other system or transport. Channel adapters may be either inbound or outbound. Typically, the channel adapter does some mapping between the message and whatever object or resource is received from or sent to the other system (file, HTTP Request, JMS message, and others). Depending on the transport, the channel adapter may also populate or extract message header values. Spring Integration provides a number of channel adapters, which are described in upcoming chapters.
MessageChannel
.
消息源可以是可轮询的(例如,POP3)或消息驱动的(例如,IMAP Idle)。在前面的图表中,这由 “clock” 符号和实线箭头(轮询)和虚线箭头(消息驱动)描绘。 |
Message sources can be pollable (for example, POP3) or message-driven (for example, IMAP Idle). In the preceding diagram, this is depicted by the “clock” symbol and the solid arrow (poll) and the dotted arrow (message-driven). |
MessageChannel
to a target system.
如前所述,Message Channel 中通道可能是可轮询的或可订阅的。在前面的图表中,这由 “clock” 符号和实线箭头(轮询)和虚线箭头(订阅)描述。 |
As discussed earlier in Message Channel, channels can be pollable or subscribable. In the preceding diagram, this is depicted by the “clock” symbol and the solid arrow (poll) and the dotted arrow (subscribe). |
Endpoint Bean Names
用户端点(任何有 inputChannel
的端点)包含两个 bean,使用者和消息处理程序。使用者对消息处理程序有引用,并且在消息到达时调用消息处理程序。
Consuming endpoints (anything with an inputChannel
) consist of two beans, the consumer and the message handler.
The consumer has a reference to the message handler and invokes it as messages arrive.
考虑以下 XML 示例:
Consider the following XML example:
<int:service-activator id = "someService" ... />
鉴于上述示例,bean 名称如下:
Given the preceding example, the bean names are as follows:
-
Consumer:
someService
(theid
) -
Handler:
someService.handler
当使用 Enterprise Integration Pattern (EIP) 注释时,名称取决于诸多因素。考虑以下带注释的 POJO 示例:
When using Enterprise Integration Pattern (EIP) annotations, the names depend on several factors. Consider the following example of an annotated POJO:
@Component
public class SomeComponent {
@ServiceActivator(inputChannel = ...)
public String someMethod(...) {
...
}
}
鉴于上述示例,bean 名称如下:
Given the preceding example, the bean names are as follows:
-
Consumer:
someComponent.someMethod.serviceActivator
-
Handler:
someComponent.someMethod.serviceActivator.handler
从版本 5.0.4 开始,您可以使用 @EndpointId
注释修改这些名称,如下例所示:
Starting with version 5.0.4, you can modify these names by using the @EndpointId
annotation, as the following example shows:
@Component
public class SomeComponent {
@EndpointId("someService")
@ServiceActivator(inputChannel = ...)
public String someMethod(...) {
...
}
}
鉴于上述示例,bean 名称如下:
Given the preceding example, the bean names are as follows:
-
Consumer:
someService
-
Handler:
someService.handler
@EndpointId
根据 XML 配置中的 id
属性创建名称。考虑以下带注释的 bean 示例:
The @EndpointId
creates names as created by the id
attribute with XML configuration.
Consider the following example of an annotated bean:
@Configuration
public class SomeConfiguration {
@Bean
@ServiceActivator(inputChannel = ...)
public MessageHandler someHandler() {
...
}
}
鉴于上述示例,bean 名称如下:
Given the preceding example, the bean names are as follows:
-
Consumer:
someConfiguration.someHandler.serviceActivator
-
Handler:
someHandler
(the@Bean
name)
从版本 5.0.4 开始,您可以使用 @EndpointId
注释修改这些名称,如下例所示:
Starting with version 5.0.4, you can modify these names by using the @EndpointId
annotation, as the following example shows:
@Configuration
public class SomeConfiguration {
@Bean("someService.handler") 1
@EndpointId("someService") 2
@ServiceActivator(inputChannel = ...)
public MessageHandler someHandler() {
...
}
}
1 | Handler: someService.handler (the bean name) |
2 | Consumer: someService (the endpoint ID) |
@EndpointId
注释根据 XML 配置中的 id
属性创建名称,只要您使用向 @Bean
名称附加 .handler
的约定。
The @EndpointId
annotation creates names as created by the id
attribute with XML configuration, as long as you use the convention of appending .handler
to the @Bean
name.
存在一个创建一个第三个 bean 的特殊情况:出于体系架构原因,如果 MessageHandler
@Bean
未定义 AbstractReplyProducingMessageHandler
,该框架会将提供的 bean 封装在 ReplyProducingMessageHandlerWrapper
中。此封装器支持请求处理程序建议处理并发出正常的“未产生答复”调试日志消息。其 bean 名称是处理程序 bean 名称加上 .wrapper
(当有 @EndpointId
时——否则,它是正常生成的处理程序名称)。
There is one special case where a third bean is created: For architectural reasons, if a MessageHandler
@Bean
does not define an AbstractReplyProducingMessageHandler
, the framework wraps the provided bean in a ReplyProducingMessageHandlerWrapper
.
This wrapper supports request handler advice handling and emits the normal 'produced no reply' debug log messages.
Its bean name is the handler bean name plus .wrapper
(when there is an @EndpointId
— otherwise, it is the normal generated handler name).
类似地,{Pollable Message Sources} 创建两个 bean,一个 {SourcePollingChannelAdapter
}(SPCA)和一个 {MessageSource
}。
Similarly, Pollable Message Sources create two beans, a SourcePollingChannelAdapter
(SPCA) and a MessageSource
.
考虑以下 XML 配置:
Consider the following XML configuration:
<int:inbound-channel-adapter id = "someAdapter" ... />
根据前面提到的 XML 配置,bean 名称如下:
Given the preceding XML configuration, the bean names are as follows:
-
SPCA:
someAdapter
(theid
) -
Handler:
someAdapter.source
考虑以下 Java 配置,以定义 POJO 到 @EndpointId
:
Consider the following Java configuration of a POJO to define an @EndpointId
:
@EndpointId("someAdapter")
@InboundChannelAdapter(channel = "channel3", poller = @Poller(fixedDelay = "5000"))
public String pojoSource() {
...
}
根据前面提到的 Java 配置示例,bean 名称如下:
Given the preceding Java configuration example, the bean names are as follows:
-
SPCA:
someAdapter
-
Handler:
someAdapter.source
考虑以下 Java 配置,以定义 bean 到 @EndpointID
:
Consider the following Java configuration of a bean to define an @EndpointID
:
@Bean("someAdapter.source")
@EndpointId("someAdapter")
@InboundChannelAdapter(channel = "channel3", poller = @Poller(fixedDelay = "5000"))
public MessageSource<?> source() {
return () -> {
...
};
}
鉴于上述示例,bean 名称如下:
Given the preceding example, the bean names are as follows:
-
SPCA:
someAdapter
-
Handler:
someAdapter.source
(as long as you use the convention of appending.source
to the@Bean
name)
Configuration and @EnableIntegration
在本文档中,您会看到 Spring Integration 流程中元素声明的 XML 命名空间支持引用的内容。此支持是由一系列命名空间解析器提供的,这些解析器会生成适当的 Bean 定义来实现特定组件。例如,许多终结点由 MessageHandler
bean 和 ConsumerEndpointFactoryBean
组成,在其中注入处理程序和输入通道名称。
Throughout this document, you can see references to XML namespace support for declaring elements in a Spring Integration flow.
This support is provided by a series of namespace parsers that generate appropriate bean definitions to implement a particular component.
For example, many endpoints consist of a MessageHandler
bean and a ConsumerEndpointFactoryBean
into which the handler and an input channel name are injected.
Spring Integration 命名空间元素首次遇到时,框架会自动声明过多 bean(任务调度程序、隐式通道创建者等),这些 bean 用于支持运行时环境。
The first time a Spring Integration namespace element is encountered, the framework automatically declares a number of beans (a task scheduler, an implicit channel creator, and others) that are used to support the runtime environment.
版本 4.0 引入了 @EnableIntegration
注解,以允许注册 Spring Integration 基础结构 Bean(参见 Javadoc)。仅在使用 Java 配置时才需要此注释——例如,使用 Spring Boot 或 Spring Integration Messaging 注解支持以及 Spring Integration Java DSL,而没有 XML 集成配置。
Version 4.0 introduced the @EnableIntegration
annotation, to allow the registration of Spring Integration infrastructure beans (see the Javadoc).
This annotation is required when only Java configuration is used — for example with Spring Boot or Spring Integration Messaging Annotation support and Spring Integration Java DSL with no XML integration configuration.
当您拥有不具有 Spring Integration 组件的父上下文和使用 Spring Integration 的两个或多个子上下文时,@EnableIntegration
注释也十分有用。它使这些公共组件只能在父上下文中声明一次。
The @EnableIntegration
annotation is also useful when you have a parent context with no Spring Integration components and two or more child contexts that use Spring Integration.
It lets these common components be declared once only, in the parent context.
@EnableIntegration
注释会向应用程序上下文注册许多基础设施组件。特别是,它:
The @EnableIntegration
annotation registers many infrastructure components with the application context.
In particular, it:
-
Registers some built-in beans, such as
errorChannel
and itsLoggingHandler
,taskScheduler
for pollers,jsonPath
SpEL-function, and others. -
Adds several
BeanFactoryPostProcessor
instances to enhance theBeanFactory
for global and default integration environment. -
Adds several
BeanPostProcessor
instances to enhance or convert and wrap particular beans for integration purposes. -
Adds annotation processors to parse messaging annotations and registers components for them with the application context.
{@IntegrationComponentScan
} 注解还允许类路径扫描。此注释发挥的作用与标准 Spring Framework {@ComponentScan
} 注释的作用类似,但它仅限于 Spring Integration 特定的组件和注释,这是标准 Spring Framework 组件扫描机制无法触及的。有关示例,请参见 {@MessagingGateway
Annotation}。
The @IntegrationComponentScan
annotation also permits classpath scanning.
This annotation plays a similar role as the standard Spring Framework @ComponentScan
annotation, but it is restricted to components and annotations that are specific to Spring Integration, which the standard Spring Framework component scan mechanism cannot reach.
For an example, see @MessagingGateway
Annotation.
@EnablePublisher
注释会注册一个 PublisherAnnotationBeanPostProcessor
bean,并为那些未提供 channel
属性的 @Publisher
注释配置 default-publisher-channel
。如果找到多个 @EnablePublisher
注释,则对于默认通道,它们必须具有相同的值。有关更多信息,请参见 Annotation-driven Configuration with the @Publisher
Annotation。
The @EnablePublisher
annotation registers a PublisherAnnotationBeanPostProcessor
bean and configures the default-publisher-channel
for those @Publisher
annotations that are provided without a channel
attribute.
If more than one @EnablePublisher
annotation is found, they must all have the same value for the default channel.
See Annotation-driven Configuration with the @Publisher
Annotation for more information.
@GlobalChannelInterceptor
注释已引入,用于标记全局通道拦截的 ChannelInterceptor
bean。此注释类似于 <int:channel-interceptor>
XML 元素(请参阅 Global Channel Interceptor Configuration)。@GlobalChannelInterceptor
注释可以放置在类级别(带有 @Component
构造型注释)或 @Configuration
类中的 @Bean
方法上。在任何情况下,bean 都必须实现 ChannelInterceptor
。
The @GlobalChannelInterceptor
annotation has been introduced to mark ChannelInterceptor
beans for global channel interception.
This annotation is an analogue of the <int:channel-interceptor>
XML element (see Global Channel Interceptor Configuration).
@GlobalChannelInterceptor
annotations can be placed at the class level (with a @Component
stereotype annotation) or on @Bean
methods within @Configuration
classes.
In either case, the bean must implement ChannelInterceptor
.
从版本 5.1 开始,全局通道拦截器适用于动态注册的通道,例如通过使用 beanFactory.initializeBean()
或在使用 Java DSL 时通过 IntegrationFlowContext
初始化的 bean。以前,在应用程序上下文刷新后创建 bean 时不应用拦截器。
Starting with version 5.1, global channel interceptors apply to dynamically registered channels — such as beans that are initialized by using beanFactory.initializeBean()
or through the IntegrationFlowContext
when using the Java DSL.
Previously, interceptors were not applied when beans were created after the application context was refreshed.
@IntegrationConverter
注释将 Converter
,GenericConverter
或 ConverterFactory
bean 标记为 integrationConversionService
的候选转换器。此注释类似于 <int:converter>
XML 元素(请参阅 Payload Type Conversion)。您可以将 @IntegrationConverter
注释放置在类级别(带有 @Component
构造型注释)或 @Configuration
类中的 @Bean
方法上。
The @IntegrationConverter
annotation marks Converter
, GenericConverter
, or ConverterFactory
beans as candidate converters for integrationConversionService
.
This annotation is an analogue of the <int:converter>
XML element (see Payload Type Conversion).
You can place @IntegrationConverter
annotations at the class level (with a @Component
stereotype annotation) or on @Bean
methods within @Configuration
classes.
有关消息传递注释的更多信息,请参见 Annotation Support。
See Annotation Support for more information about messaging annotations.
Programming Considerations
您应尽可能使用普通的旧 Java 对象 (POJO),并且只有在绝对必要时,才会在代码中公开框架。有关更多信息,请参见 POJO Method invocation。
You should use plain old java objects (POJOs) whenever possible and only expose the framework in your code when absolutely necessary. See POJO Method invocation for more information.
如果您确实向您的类公开了该框架,则需要考虑一些注意事项,尤其是在应用程序启动期间:
If you do expose the framework to your classes, there are some considerations that need to be taken into account, especially during application startup:
-
If your component is
ApplicationContextAware
, you should generally not use theApplicationContext
in thesetApplicationContext()
method. Instead, store a reference and defer such uses until later in the context lifecycle. -
If your component is an
InitializingBean
or uses@PostConstruct
methods, do not send any messages from these initialization methods. The application context is not yet initialized when these methods are called, and sending such messages is likely to fail. If you need to send a messages during startup, implementApplicationListener
and wait for theContextRefreshedEvent
. Alternatively, implementSmartLifecycle
, put your bean in a late phase, and send the messages from thestart()
method.
Considerations When Using Packaged (for example, Shaded) Jars
Spring Integration 通过使用 Spring Framework 的 SpringFactories
机制来加载多个 IntegrationConfigurationInitializer
类来引导某些功能。这包括 -core
jar 以及某些其他 jar,包括 -http
和 -jmx
。此流程的信息存储在每个 jar 中的 META-INF/spring.factories
文件中。
Spring Integration bootstraps certain features by using Spring Framework’s SpringFactories
mechanism to load several IntegrationConfigurationInitializer
classes.
This includes the -core
jar as well as certain others, including -http
and -jmx
.
The information for this process is stored in a META-INF/spring.factories
file in each jar.
一些开发人员更喜欢使用众所周知的工具(如 Apache Maven Shade Plugin)将应用程序及其所有依赖项重新打包到一个 Jar 中。
Some developers prefer to repackage their application and all dependencies into a single jar by using well known tools, such as the Apache Maven Shade Plugin.
默认情况下,在生成遮盖 jar 时,遮盖插件不会合并 spring.factories
文件。
By default, the shade plugin does not merge the spring.factories
files when producing the shaded jar.
除 spring.factories
以外,其他 META-INF
文件 (spring.handlers
和 spring.schemas
) 用于 XML 配置。这些文件也需要合并。
In addition to spring.factories
, other META-INF
files (spring.handlers
and spring.schemas
) are used for XML configuration.
These files also need to be merged.
Spring Boot’s executable jar mechanism 采取不同的方法,它嵌套 JAR,从而保留类路径上的每个 spring.factories
文件。因此,对于 Spring Boot 应用程序,如果你使用其默认的可执行 JAR 格式,则不需要做任何其他事情。
Spring Boot’s executable jar mechanism takes a different approach, in that it nests the jars, thus retaining each spring.factories
file on the class path.
So, with a Spring Boot application, nothing more is needed if you use its default executable jar format.
即使您不使用 Spring Boot,您仍然可以使用 Boot 提供的工具通过添加上述文件的转换器来增强 shade 插件。以下示例展示了如何配置插件:
Even if you do not use Spring Boot, you can still use the tooling provided by Boot to enhance the shade plugin by adding transformers for the above mentioned files. The following example shows how to configure the plugin:
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope>
<createDependencyReducedPom>true</createDependencyReducedPom>
</configuration>
<dependencies>
<dependency> 1
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers> 2
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer
implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
具体而言,
Specifically,
1 | Add the spring-boot-maven-plugin as a dependency. |
2 | Configure the transformers. |
您可以为 ${spring.boot.version}
添加属性,或使用显式版本。
You can add a property for ${spring.boot.version}
or use an explicit version.
Programming Tips and Tricks
此部分文件记录了一些从 Spring Integration 中获得最大收益的方法。
This section documents some ways to get the most from Spring Integration.
XML Schemas
在使用 XML 配置时,为避免收到错误的模式验证错误,您应该使用“支持 Spring”的 IDE,例如 Spring Tool Suite (STS)、带有 Spring IDE 插件的 Eclipse 或 IntelliJ IDEA。这些 IDE 知道如何从类路径(通过 jar 中的 META-INF/spring.schemas
文件)解析正确的 XML 模式。在使用带有插件的 STS 或 Eclipse 时,您必须在项目中启用“Spring Project Nature”。
When using XML configuration, to avoid getting false schema validation errors, you should use a “Spring-aware” IDE, such as the Spring Tool Suite (STS), Eclipse with the Spring IDE plugins, or IntelliJ IDEA.
These IDEs know how to resolve the correct XML schema from the classpath (by using the META-INF/spring.schemas
file in the jars).
When using STS or Eclipse with the plugin, you must enable Spring Project Nature
on the project.
为了兼容性原因,某些旧模块(存在于 1.0 版本中的)在互联网上托管的模式是 1.0 版本。如果您的 IDE 使用这些模式,则可能会看到错误的错误。
The schemas hosted on the internet for certain legacy modules (those that existed in version 1.0) are the 1.0 versions for compatibility reasons. If your IDE uses these schemas, you are likely to see false errors.
每个这些在线模式都有类似于以下内容的警告:
Each of these online schemas has a warning similar to the following:
这个模式是 Spring Integration Core 的 1.0 版本。我们无法将其更新为当前模式,因为这将破坏任何使用 1.0.3 或更低版本的应用程序。对于后续版本,“未加版本”的模式是从类路径解析并从 jar 中获取的。请参阅 GitHub:
This schema is for the 1.0 version of Spring Integration Core. We cannot update it to the current schema because that will break any applications using 1.0.3 or lower. For subsequent versions, the "unversioned" schema is resolved from the classpath and obtained from the jar. Please refer to GitHub:
受影响的模块为
The affected modules are
-
core
(spring-integration.xsd
) -
file
-
http
-
jms
-
mail
-
security
-
stream
-
ws
-
xml
Finding Class Names for Java and DSL Configuration
使用 XML 配置和 Spring Integration Namespace 支持,XML 解析器隐藏了目标 Bean 的声明方式,以及它们如何连接在一起。对于 Java 配置,了解针对最终用户应用程序的 Framework API 非常重要。
With XML configuration and Spring Integration Namespace support, the XML parsers hide how target beans are declared and wired together. For Java configuration, it is important to understand the Framework API for target end-user applications.
EIP 实现的一等公民是 Message
、 Channel
和 Endpoint
(参见本章前面的 Main Components)。它们的实现(契约)为:
The first-class citizens for EIP implementation are Message
, Channel
, and Endpoint
(see Main Components, earlier in this chapter).
Their implementations (contracts) are:
-
org.springframework.messaging.Message
: See Message; -
org.springframework.messaging.MessageChannel
: See Message Channels; -
org.springframework.integration.endpoint.AbstractEndpoint
: See Poller.
前两个足够简单,可以理解如何实现、配置和使用。最后一个需要更多的关注
The first two are simple enough to understand how to implement, configure, and use. The last one deserves more attention
AbstractEndpoint
在 Spring Framework 中广泛用于不同的组件实现。其主要实现是:
The AbstractEndpoint
is widely used throughout the Spring Framework for different component implementations.
Its main implementations are:
-
EventDrivenConsumer
, used when we subscribe to aSubscribableChannel
to listen for messages. -
PollingConsumer
, used when we poll for messages from aPollableChannel
.
当您使用消息传递注释或 Java DSL 时,您不必担心这些组件,因为 Framework 会自动使用适当的注释和 BeanPostProcessor
实现生成它们。在手动构建组件时,您应该使用 ConsumerEndpointFactoryBean
帮助确定要创建的目标 AbstractEndpoint
消费者实现,具体基于提供的 inputChannel
属性。
When you use messaging annotations or the Java DSL, you don’t need to worry about these components, because the Framework automatically produces them with appropriate annotations and BeanPostProcessor
implementations.
When building components manually, you should use the ConsumerEndpointFactoryBean
to help determine the target AbstractEndpoint
consumer implementation to create, based on the provided inputChannel
property.
另一方面,ConsumerEndpointFactoryBean
委托给框架中的另一个一等公民-org.springframework.messaging.MessageHandler
。实现此界面的目的是处理来自通道的端点使用的消息。Spring Integration 中的所有 EIP 组件均为 MessageHandler
实现(例如,AggregatingMessageHandler
、MessageTransformingHandler
、AbstractMessageSplitter
等)。目标协议出站适配器(FileWritingMessageHandler
、HttpRequestExecutingMessageHandler
、AbstractMqttMessageHandler
等)也是 MessageHandler
实现。使用 Java 配置开发 Spring Integration 应用程序时,您应该查看 Spring Integration 模块以查找适合用于 @ServiceActivator
配置的 MessageHandler
实现。例如,要发送 XMPP 消息(参见 XMPP Support),您应该配置类似以下内容:
On the other hand, the ConsumerEndpointFactoryBean
delegates to an another first class citizen in the Framework - org.springframework.messaging.MessageHandler
.
The goal of the implementation of this interface is to handle the message consumed by the endpoint from the channel.
All EIP components in Spring Integration are MessageHandler
implementations (for example, AggregatingMessageHandler
, MessageTransformingHandler
, AbstractMessageSplitter
, and others).
The target protocol outbound adapters (FileWritingMessageHandler
, HttpRequestExecutingMessageHandler
, AbstractMqttMessageHandler
, and others) are also MessageHandler
implementations.
When you develop Spring Integration applications with Java configuration, you should look into the Spring Integration module to find an appropriate MessageHandler
implementation to use for the @ServiceActivator
configuration.
For example, to send an XMPP message (see XMPP Support) you should configure something like the following:
@Bean
@ServiceActivator(inputChannel = "input")
public MessageHandler sendChatMessageHandler(XMPPConnection xmppConnection) {
ChatMessageSendingMessageHandler handler = new ChatMessageSendingMessageHandler(xmppConnection);
DefaultXmppHeaderMapper xmppHeaderMapper = new DefaultXmppHeaderMapper();
xmppHeaderMapper.setRequestHeaderNames("*");
handler.setHeaderMapper(xmppHeaderMapper);
return handler;
}
MessageHandler
实现表示消息流的出站和处理部分。
The MessageHandler
implementations represent the outbound and processing part of the message flow.
入站消息流方面有其自身组件,它们分为轮询和侦听行为。侦听(消息驱动的)组件简单,通常只需要一个目标类实现即可生成消息。侦听组件可以是一次性的 MessageProducerSupport
实现(例如 AbstractMqttMessageDrivenChannelAdapter
和 ImapIdleChannelAdapter
),或请求答复 MessagingGatewaySupport
实现(例如 AmqpInboundGateway
和 AbstractWebServiceInboundGateway
)。
The inbound message flow side has its own components, which are divided into polling and listening behaviors.
The listening (message-driven) components are simple and typically require only one target class implementation to be ready to
produce messages.
Listening components can be one-way MessageProducerSupport
implementations, (such as AbstractMqttMessageDrivenChannelAdapter
and ImapIdleChannelAdapter
) or request-reply MessagingGatewaySupport
implementations (such as AmqpInboundGateway
and AbstractWebServiceInboundGateway
).
轮询入站端点适合那些不提供侦听器 API 或不适用于此类行为的协议,包括基于文件的协议(如 FTP)、任何数据库(RDBMS 或 NoSQL)等。
Polling inbound endpoints are for those protocols that do not provide a listener API or are not intended for such a behavior, including any file based protocol (such as FTP), any data bases (RDBMS or NoSQL), and others.
这些入站端点包含两个组件:轮询程序配置,用于定期启动轮询任务;以及消息源类,用于从目标协议读取数据并为下游集成流生成消息。轮询程序配置的第一个类是 SourcePollingChannelAdapter
。它是另一个 AbstractEndpoint
实现,但专门用于轮询以启动集成流。通常,使用消息批注或 Java DSL 时,不必担心此类。框架会根据 @InboundChannelAdapter
配置或 Java DSL 构建器规范为此类生成一个 bean。
These inbound endpoints consist of two components: the poller configuration, to initiate the polling task periodically,
and a message source class to read data from the target protocol and produce a message for the downstream integration flow.
The first class for the poller configuration is a SourcePollingChannelAdapter
.
It is one more AbstractEndpoint
implementation, but especially for polling to initiate an integration flow.
Typically, with the messaging annotations or Java DSL, you should not worry about this class.
The Framework produces a bean for it, based on the @InboundChannelAdapter
configuration or a Java DSL builder spec.
消息源组件对目标应用程序开发更为重要,并且它们全部实现 MessageSource
接口(例如 MongoDbMessageSource
和 AbstractTwitterMessageSource
)。牢记这一点,我们用于从 JDBC 读取 RDBMS 表数据的配置可以类似以下内容:
Message source components are more important for the target application development, and they all implement the MessageSource
interface (for example, MongoDbMessageSource
and AbstractTwitterMessageSource
).
With that in mind, our config for reading data from an RDBMS table with JDBC could resemble the following:
@Bean
@InboundChannelAdapter(value = "fooChannel", poller = @Poller(fixedDelay="5000"))
public MessageSource<?> storedProc(DataSource dataSource) {
return new JdbcPollingChannelAdapter(dataSource, "SELECT * FROM foo where status = 0");
}
您可以在特定的 Spring 集成模块中查找目标协议所需的所有入站和出站类(在大多数情况下,在各自的包中)。例如,spring-integration-websocket
适配器为:
You can find all the required inbound and outbound classes for the target protocols in the particular Spring Integration module (in most cases, in the respective package).
For example, the spring-integration-websocket
adapters are:
-
o.s.i.websocket.inbound.WebSocketInboundChannelAdapter
: ImplementsMessageProducerSupport
to listen for frames on the socket and produce message to the channel. -
o.s.i.websocket.outbound.WebSocketOutboundMessageHandler
: The one-wayAbstractMessageHandler
implementation to convert incoming messages to the appropriate frame and send over websocket.
如果您熟悉 Spring 集成的 XML 配置,从 4.3 版开始,我们将在 XSD 元素定义中提供有关用于声明适配器或网关 bean 的目标类的信息,如以下示例所示:
If you are familiar with Spring Integration XML configuration, starting with version 4.3, we provide information in the XSD element definitions about which target classes are used to declare beans for the adapter or gateway, as the following example shows:
<xsd:element name="outbound-async-gateway">
<xsd:annotation>
<xsd:documentation>
Configures a Consumer Endpoint for the 'o.s.i.amqp.outbound.AsyncAmqpOutboundGateway'
that will publish an AMQP Message to the provided Exchange and expect a reply Message.
The sending thread returns immediately; the reply is sent asynchronously; uses 'AsyncRabbitTemplate.sendAndReceive()'.
</xsd:documentation>
</xsd:annotation>
POJO Method invocation
正如在 Programming Considerations 中所讨论的,我们建议使用 POJO 编程风格,如下例所示:
As discussed in Programming Considerations, we recommend using a POJO programming style, as the following example shows:
@ServiceActivator
public String myService(String payload) { ... }
在这种情况下,框架将提取 String
有效负载、调用您的方法,并将结果包装成消息,以便发送到流中的下一个组件(原始标题将复制到新消息中)。事实上,如果您使用 XML 配置,则甚至不需要 @ServiceActivator
批注,如以下配对示例所示:
In this case, the framework extracts a String
payload, invokes your method, and wraps the result in a message to send to the next component in the flow (the original headers are copied to the new message).
In fact, if you use XML configuration, you do not even need the @ServiceActivator
annotation, as the following paired examples show:
<int:service-activator ... ref="myPojo" method="myService" />
public String myService(String payload) { ... }
只要类上的公共方法中没有歧义,就可以省略 method
属性。
You can omit the method
attribute as long as there is no ambiguity in the public methods on the class.
您还可以在 POJO 方法中获取标题信息,如以下示例所示:
You can also obtain header information in your POJO methods, as the following example shows:
@ServiceActivator
public String myService(@Payload String payload, @Header("foo") String fooHeader) { ... }
您还可以取消引用消息上的属性,如以下示例所示:
You can also dereference properties on the message, as the following example shows:
@ServiceActivator
public String myService(@Payload("payload.foo") String foo, @Header("bar.baz") String barbaz) { ... }
由于可以使用多种 POJO 方法调用,因此 5.0 之前的版本会使用 SpEL(Spring 表达式语言)来调用 POJO 方法。与在方法中通常执行的实际工作相比,SpEL(甚至是已解释的)对于这些操作通常是“足够快”的。但是,从 5.0 版本开始,只要有可能,默认情况下将使用 org.springframework.messaging.handler.invocation.InvocableHandlerMethod
。此技术的执行速度通常比已解释的 SpEL 更快,并且与其他 Spring 消息传递项目一致。InvocableHandlerMethod
类似于在 Spring MVC 中用来调用控制器方法的技术。在使用 SpEL 时,仍然总有一些方法会被调用。示例包括前面讨论过的带取消引用属性的批注参数。这是因为 SpEL 具有导航属性路径的能力。
Because various POJO method invocations are available, versions prior to 5.0 used SpEL (Spring Expression Language) to invoke the POJO methods.
SpEL (even interpreted) is usually “fast enough” for these operations, when compared to the actual work usually done in the methods.
However, starting with version 5.0, the org.springframework.messaging.handler.invocation.InvocableHandlerMethod
is used by default whenever possible.
This technique is usually faster to execute than interpreted SpEL and is consistent with other Spring messaging projects.
The InvocableHandlerMethod
is similar to the technique used to invoke controller methods in Spring MVC.
There are certain methods that are still always invoked when using SpEL.
Examples include annotated parameters with dereferenced properties, as discussed earlier.
This is because SpEL has the capability to navigate a property path.
还有一些我们尚未考虑的边缘情况也不适用于 InvocableHandlerMethod
实例。因此,在这些情况下,我们会自动退回到使用 SpEL。
There may be some other corner cases that we have not considered that also do not work with InvocableHandlerMethod
instances.
For this reason, we automatically fall back to using SpEL in those cases.
如果您愿意,还可以使用 UseSpelInvoker
批注设置 POJO 方法,使其始终使用 SpEL,如以下示例所示:
If you wish, you can also set up your POJO method such that it always uses SpEL, with the UseSpelInvoker
annotation, as the following example shows:
@UseSpelInvoker(compilerMode = "IMMEDIATE")
public void bar(String bar) { ... }
如果省略 compilerMode
属性,则 spring.expression.compiler.mode
系统属性会确定编译器模式。有关已编译 SpEL 的更多信息,请参见 SpEL compilation。
If the compilerMode
property is omitted, the spring.expression.compiler.mode
system property determines the compiler mode.
See SpEL compilation for more information about compiled SpEL.