303 lines
19 KiB
XML
303 lines
19 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|
<chapter id="overview">
|
|
<title>Spring Integration Overview</title>
|
|
|
|
<section id="overview-background">
|
|
<title>Background</title>
|
|
<para>
|
|
One of the key themes of the Spring Framework is <emphasis>inversion of control</emphasis>. 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 since they are relieved of those responsibilities. For
|
|
example, <emphasis>dependency injection</emphasis> relieves the components of the responsibility of locating or
|
|
creating their dependencies. Likewise, <emphasis>aspect-oriented programming</emphasis> 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.
|
|
</para>
|
|
<para>
|
|
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 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.
|
|
</para>
|
|
<para>
|
|
Spring Integration is a new member of the Spring portfolio 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 <emphasis>when</emphasis> certain business logic
|
|
should execute and <emphasis>where</emphasis> 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, so business
|
|
components are further isolated from the infrastructure and developers are relieved of complex integration
|
|
responsibilities.
|
|
</para>
|
|
<para>
|
|
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 of course 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 <ulink url="http://www.eaipatterns.com">Enterprise Integration Patterns</ulink>
|
|
as described in the book of the same name 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.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-goalsandprinciples">
|
|
<title>Goals and Principles</title>
|
|
<para>Spring Integration is motivated by the following goals:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Provide a simple model for implementing complex enterprise integration solutions.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Facilitate asynchronous, message-driven behavior within a Spring-based application.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Promote intuitive, incremental adoption for existing Spring users.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>Spring Integration is guided by the following principles:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Components should be <emphasis>loosely coupled</emphasis> for modularity and testability.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>The framework should enforce <emphasis>separation of concerns</emphasis> between business logic and
|
|
integration logic.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>Extension points should be abstract in nature but within well-defined boundaries to promote
|
|
<emphasis>reuse</emphasis> and <emphasis>portability</emphasis>.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-components">
|
|
<title>Main Components</title>
|
|
<para>
|
|
From the <emphasis>vertical</emphasis> 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
|
|
<emphasis>horizontal</emphasis> 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 component that is capable of producing and/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 would typically be managed within a layer
|
|
that is logically above the application's service layer, interacting with those services through interfaces much
|
|
in the same way that a web-tier would.
|
|
</para>
|
|
|
|
<section id="overview-components-message">
|
|
<title>Message</title>
|
|
<para>
|
|
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, expiration, 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, etc.) may be configured as Message header values by an upstream component. Developers can also
|
|
store any arbitrary key-value pairs in the headers.
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata align="center" fileref="images/message.png" format="PNG"/>
|
|
</imageobject>
|
|
</mediaobject>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-components-channel">
|
|
<title>Message Channel</title>
|
|
<para>
|
|
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.
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata align="center" fileref="images/channel.png" format="PNG"/>
|
|
</imageobject>
|
|
</mediaobject>
|
|
A Message Channel may follow either Point-to-Point or Publish/Subscribe semantics. With a Point-to-Point
|
|
channel, at most one consumer can receive each Message sent to the channel. Publish/Subscribe channels, on the
|
|
other hand, will attempt to broadcast each Message to all of its subscribers. Spring Integration supports
|
|
both of these.
|
|
</para>
|
|
<para>
|
|
Whereas "Point-to-Point" and "Publish/Subscribe" define the two options for <emphasis>how many</emphasis>
|
|
consumers will ultimately receive each Message, there is another important consideration: should the channel
|
|
buffer messages? In Spring Integration, <emphasis>Pollable Channels</emphasis> 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 <emphasis>poller</emphasis> is configured. On
|
|
the other hand, a consumer connected to a <emphasis>Subscribable Channel</emphasis> is simply Message-driven.
|
|
The variety of channel implementations available in Spring Integration will be discussed in detail in
|
|
<xref linkend="channel-implementations"/>.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-components-endpoint">
|
|
<title>Message Endpoint</title>
|
|
<para>
|
|
One of the primary goals of Spring Integration is to simplify the development of enterprise integration
|
|
solutions through <emphasis>inversion of control</emphasis>. 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 will necessarily connect
|
|
your existing application code directly. Any real-world enterprise integration solution will require some
|
|
amount of code focused upon integration concerns such as <emphasis>routing</emphasis> and
|
|
<emphasis>transformation</emphasis>. The important thing is to achieve separation of concerns between such
|
|
integration logic and business logic. In other words, as with the Model-View-Controller 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 will provide an overview of the Message Endpoint types that handle these responsibilities, and in
|
|
upcoming chapters, you will see how Spring Integration's declarative configuration options provide a
|
|
non-invasive way to use each of these.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="overview-endpoints">
|
|
<title>Message Endpoints</title>
|
|
<para>
|
|
A Message Endpoint represents the "filter" of a pipes-and-filters architecture. As mentioned above, 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 are discussed at length along with all of the patterns that follow in the
|
|
<ulink url="http://www.eaipatterns.com">Enterprise Integration Patterns</ulink> book. Here, we provide only a
|
|
high-level description of the main endpoint types supported by Spring Integration and their roles. The chapters
|
|
that follow will elaborate and provide sample code as well as configuration examples.
|
|
</para>
|
|
|
|
<section id="overview-endpoints-transformer">
|
|
<title>Transformer</title>
|
|
<para>
|
|
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 (e.g. from XML Document to java.lang.String). Similarly, a transformer may be used to add,
|
|
remove, or modify the Message's header values.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-endpoints-filter">
|
|
<title>Filter</title>
|
|
<para>
|
|
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, etc. If the Message is accepted, it is sent to the output channel, but if not it will be
|
|
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
|
|
filter to narrow down the set of Messages to be processed based on some criteria.
|
|
<note>
|
|
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 "filter" matches more closely with Spring Integration's Message Endpoint: any
|
|
component that can be connected to Message Channel(s) in order to send and/or receive Messages.
|
|
</note>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-endpoints-router">
|
|
<title>Router</title>
|
|
<para>
|
|
A Message Router is responsible for deciding what channel or channels should receive the Message next (if any).
|
|
Typically the decision is based upon the Message's content and/or 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 above.
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata align="center" fileref="images/router.png" format="PNG"/>
|
|
</imageobject>
|
|
</mediaobject>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-endpoints-splitter">
|
|
<title>Splitter</title>
|
|
<para>
|
|
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 then 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
|
|
sub-divided payloads.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-endpoints-aggregator">
|
|
<title>Aggregator</title>
|
|
<para>
|
|
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 or to discard them to a separate channel. Spring Integration provides
|
|
a <interfacename>CompletionStrategy</interfacename> as well as configurable settings for timeout, whether
|
|
to send partial results upon timeout, and the discard channel.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-endpoints-service-activator">
|
|
<title>Service Activator</title>
|
|
<para>
|
|
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.
|
|
<note>
|
|
The output channel is optional, since each Message may also provide its own 'Return Address' header. This
|
|
same rule applies for all consumer endpoints.
|
|
</note>
|
|
The Service Activator invokes an operation on some service object to process the request Message, extracting
|
|
the request Message's payload and converting if necessary (if the method does not expect a Message-typed
|
|
parameter). Whenever the service object's method returns a value, that return value will likewise be converted
|
|
to a reply Message if necessary (if it's not already a Message). That reply Message is sent to the output
|
|
channel. If no output channel has been configured, then the reply will be sent to the channel specified in the
|
|
Message's "return address" if available.
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata align="center" fileref="images/handler-endpoint.png" format="PNG"/>
|
|
</imageobject>
|
|
<caption>
|
|
A request-reply "Service Activator" endpoint connects a target object's method to input and output
|
|
Message Channels.
|
|
</caption>
|
|
</mediaobject>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="overview-endpoints-channeladapter">
|
|
<title>Channel Adapter</title>
|
|
<para>
|
|
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 will do some mapping between the
|
|
Message and whatever object or resource is received-from or sent-to the other system (File, HTTP Request, JMS
|
|
Message, etc). Depending on the transport, the Channel Adapter may also populate or extract Message header
|
|
values. Spring Integration provides a number of Channel Adapters, and they will be described in upcoming
|
|
chapters.
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata align="center" fileref="images/source-endpoint.png" format="PNG"/>
|
|
</imageobject>
|
|
<caption>An inbound "Channel Adapter" endpoint connects a source system to a MessageChannel.</caption>
|
|
</mediaobject>
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata align="center" fileref="images/target-endpoint.png" format="PNG"/>
|
|
</imageobject>
|
|
<caption>An outbound "Channel Adapter" endpoint connects a MessageChannel to a target system.</caption>
|
|
</mediaobject>
|
|
</para>
|
|
</section>
|
|
</section>
|
|
|
|
</chapter> |