List of Figures
Chapter 1. Introduction to Spring Integration
Figure 1.1. Two areas of focus for Spring Integration: lightweight intra-application messaging and flexible interapplication
integration
Figure 1.2. A message is passed through a channel from one endpoint to another endpoint.
Figure 1.3. A message consists of a single payload and zero or more headers, represented here by the square and circle, respectively.
Figure 1.4. A Point-to-Point Channel
Figure 1.5. A Publish-Subscribe Channel
Figure 1.6. Channel Adapter
Figure 1.7. Messaging Gateway
Figure 1.8. Messaging Gateway and Channel Adapters
Figure 1.9. Service Activator
Figure 1.10. Router
Figure 1.11. Splitter
Figure 1.12. Aggregator
Chapter 2. Enterprise integration fundamentals
Figure 2.1. A highly coupled system: components become entangled because of the complex relationships between them.
Figure 2.2. Synchronous invocation: the requester suspends execution until it receives an answer.
Figure 2.3. Asynchronous invocation: the requester doesn’t block and executes in parallel with the provider.
Figure 2.4. Synchronous message exchange: the message is received immediately by the provider.
Figure 2.5. Asynchronous message exchange: the message is stored in an intermediate buffer before being received by the provider.
Figure 2.6. Wiring of the order processing system: channels and endpoints define the logical application structure.
Figure 2.7. Synchronous order processing: the continuous line indicates an uninterrupted thread of control along the entire
processing path.
Figure 2.8. Asynchronous order processing: the introduction of a buffered channel creates two threads of control (indicated
by a continuous line)—delivery to the router takes place in and processing takes place in .
Chapter 3. Messages and channels
Figure 3.1. Creating a message with the MessageBuilder
Figure 3.2. Diagram of threading model of service invocation in the airline application
Figure 3.3. Diagram of threading model of service invocation when using a default channel
Figure 3.4. Diagram of threading model of service invocation when using a QueueChannel
Figure 3.5. Diagram of transactional boundaries when a QueueChannel is used
Chapter 4. Message Endpoints
Figure 4.1. Behavior of an inbound endpoint. Input is taken from an external source and then converted into a message, which
is sent to a channel. This image doesn’t show the optional reply message.
Figure 4.2. Behavior of an outbound endpoint. First a message is received from a channel; then the message is converted into
something the external component understands. Finally the external API is invoked. The optional result is ignored in this
image.
Figure 4.3. Transaction boundaries are determined by the scope of a given thread’s responsibility, so the transactional context
doesn’t propagate across an asynchronous channel.
Chapter 5. Getting down to business
Figure 5.1. Three different representations of the flight object. Separate transformations (T, μ, and Ø) transform a Flight
domain object into CSV, JavaScript Object Notation (JSON), and XML representations respectively.
Figure 5.2. A transformer that unmarshals a flight from XML to a domain object
Figure 5.3. A transformer that uses a repository to enrich a message. The incoming message is just a string containing the
flight number and the delay. The enricher retrieves the flight from the repository and calculates a date that represents the
delay.
Figure 5.4. Pipeline configuration with three services. A message is deconstructed and reconstructed at each service activator.
The payload is fed into the service, and the return value is used to construct a new message. The headers of the message remain
the same, so the overall context is preserved throughout the pipeline.
Figure 5.5. Endpoints can be chained together with channels implicitly created using a chain element.
Figure 5.6. The frequentFlyerService transformer, the header enricher, and the mailSender chained together
Chapter 6. Go beyond sequential processing: routing and filtering
Figure 6.1. A message filter evaluates incoming messages. Only A’s are published to the next channel, whereas B’s and C’s
are discarded.
Figure 6.2. A publish-subscribe channel and filters combination for selective processing. The first subscriber is interested
only in A’s; the second, only in B’s; and the third, in B’s and C’s.
Figure 6.3. The router at work. Any message published to payments is routed to either credit-card-payments, invoices, or paypal-payments.
Figure 6.4. Sequence diagram of the MessageFilter: a MessageSelector’s accept() method evaluates the message to decide if
it should be sent further.
Figure 6.5. Sequence diagram of the AbstractMessageRouter: the determineTargetChannels method decides the next destinations
Chapter 7. Splitting and aggregating messages
Figure 7.1. Examples of endpoints processing a message in one-to-one, one-to-many, and many-to-one scenarios
Figure 7.2. An aggregator is an endpoint that combines several related messages into one message.
Figure 7.3. The flow of messages in the home cooking example
Figure 7.4. Before the timeout, just two out of three messages have arrived. On the timeout, the aggregator sums 1 and 3 and
sends the aggregate (4). A bit later, it receives the missing 2, which it must send out without the rest of the aggregate.
Figure 7.5. The needed ingredient is scattered over all shopping lists and sent to each shop (A and B). The gatherer decides,
on the basis of the best-before date (or some other criterion), what is the best product to use and sends that to the mise
en place (not in this picture).
Figure 7.6. The CorrelatingMessageHandler and its collaborators
Chapter 8. Handling messages with XML payloads
Figure 8.1. The trip unmarshaller implements the Unmarshaller interface and can convert trip XML messages to instances of
the Trip class.
Figure 8.2. Splitting our request into the constituent parts
Figure 8.3. Routing the parts with XPath
Chapter 9. Spring Integration and the Java Message Service
Figure 9.1. The top configuration shows interprocess integration using JMS. The bottom configuration shows intraprocess integration
using Spring Integration. Which type of integration is appropriate depends on the architecture of the application.
Figure 9.2. Design of the destination-backed channel of Spring Integration. It benefits from the guarantees supported by a
JMS implementation, but it hides the JMS API behind a channel abstraction.
Figure 9.3. Spring Integration and JMS messages in a side-by-side comparison. The terminology is different, but the structure
is the same.
Figure 9.4. A pair of gateways, one outbound and the other inbound. Each is hosted by a separate Spring Integration application.
Those two applications share access to a common JMS broker and a pair of destinations.
Chapter 10. Email-based integration
Figure 10.1. Sending email requires a channel adapter and includes optional transformers for preparing outbound messages.
Figure 10.2. Spring Integration uses the mail sending layer provided by the Spring Framework proper. The components from each
layer, as well as the mail message abstractions, are shown on the right side.
Figure 10.3. Receiving emails requires a channel adapter and includes optional transformers for extracting message content.
Chapter 11. Filesystem integration
Figure 11.1. A file is picked up by the inbound adapter; it then flows through the transformer. The UI interprets the change
and sends changes made by its user back to the working directory.
Figure 11.2. Schematic design of the Spring Integration file outbound channel adapter. The outbound adapter is a passive component
that responds to incoming messages by writing their payloads to a file.
Figure 11.3. The writing leg of the collaborative editor: a String is passed to the <file:outbound-channel-adapter/> as a
message. The String payload is then converted to a file in the work directory.
Figure 11.4. Design of the Spring Integration inbound channel adapter
Figure 11.5. Inbound components of the collaborative editor: a file is picked up from the working directory and sent on the
incomingFiles channel wrapped in a message. It’s then transformed into a String and passed along to the editor.
Figure 11.6. Internal behavior of the FileReadingMessageSource when polled: (1) get a listing of the input directory, (2)
filter the resulting list, (3) add the listed files to the internal queue, and (4) return the head of the queue wrapped in
a message.
Chapter 12. Spring Integration and web services
Figure 12.1. Integration over HTTP is simple because the network exists and HTTP traffic passes relatively easily in and out
of enterprise networks.
Chapter 13. Chatting and tweeting
Figure 13.1. XMPP supports full-duplex messaging, meaning that communication occurs bidirectionally, even simultaneously.
Chapter 14. Monitoring and management
Figure 14.1. A publish-subscribe channel enables multiple downstream message flows but doesn’t make any clear distinction
between secondary and primary flows.
Figure 14.2. A Wire Tap connected to a channel enables a flow with cross-cutting behavior to be added while maintaining a
clean separation from the primary message flow.
Chapter 15. Managing scheduling and concurrency
Figure 15.1. Event-driven components receive messages directly from their invokers.
Figure 15.2. Polling components receive messages indirectly. The picture shows a typical scenario for a polling endpoint:
the invoker sends the message to a buffered channel , and the polling endpoint receives it by polling the channel .
Figure 15.3. Fixed-delay polling versus fixed-rate polling . A fixed-rate scenario guarantees that polling will happen at
the same preset interval, but the gap between poll operations completing and starting may vary. A fixed-delay scenario guarantees
that the interval between polls is constant, but the timing of the polling event may drift over time.
Figure 15.4. The effect of using max-messages-per-poll: with a value of 1, the messages are processed one by one, and the
second message has to wait for a complete polling cycle in order to get processed (top). With a value of 2, the messages are
processed as part of the same polling cycle (bottom).
Figure 15.5. The car assembly operation consists of assembling and painting. The two stages can be executed in the same thread
or asynchronously.
Figure 15.6. The difference between the single-threaded and concurrent approach. Scenario is single-threaded. Scenario is
concurrent: the assembly and paint take place in parallel, which increases the processing speed.
Chapter 16. Batch applications and enterprise integration
Figure 16.1. Online versus batch processing: requests are processed individually or as a group respectively
Figure 16.2. A typical ETL job: data is extracted from an external source, transformed, and loaded into the target
Figure 16.3. A simple batch job definition: the transactions are loaded from the input file , parsed , processed , and written
to the database
Figure 16.4. Chunk-oriented step: items are read individually by the ItemReader, optionally processed by the ItemProcessor,
then written in bulk by the ItemWriter
Figure 16.5. The relationship between Spring Batch entities: Job and Step define the logic of a job, JobExecution and StepExecution
are used to save the state, and JobParameters customizes a specific job instance
Figure 16.6. Event-driven batch job launch: the file channel adapter monitors a directory , a file message is converted to
a JobLaunchRequest , which triggers the batch job launch ( ). Other components may trigger a launch by sending a File payload
.
Figure 16.7. Handling batch events using informational messages
Figure 16.8. A gateway is used as an ItemProcessor.
Figure 16.9. Externalizing chunk processing by using a gateway
Chapter 17. Scaling messaging applications with OSGi
Figure 17.1. On an OSGi platform (bottom), you can run bundles that make use of Gemini Blueprint (middle). Spring Integration
(top) can be used in combination with Gemini Blueprint to combine messaging with dynamic loading characteristics.
Figure 17.2. The integration team sets up the server and deploys some basic bundles to it. The Short Message Service (SMS)
team develops an SMS bundle to replace the basic receiver for notifications. In parallel, the integration team replaces the
basic notifier with a bus so they can connect multiple sources of notifications. The flight notifications team writes a flight
notifier bundle that works with the bus, and in the meantime, the bus and the SMS service are deployed. The obsolete basic
bundles are uninstalled as their replacements kick in. The new bundles are working in concert, and replacement versions for
individual bundles can be deployed as needed without bringing the system down.
Figure 17.3. Modularity and it’s runtime representation in Java
Figure 17.4. OSGi specifies a clear lifecycle for bundles. In contrast to plain Java, where class loading is out of the developer’s
control, bundles can be installed, uninstalled, started, and stopped as needed. The transitions between states, as depicted
by the arrows, are clearly defined and restricted by the standard.
Figure 17.5. Inside the META-INF directory, we see the MANIFEST.MF file which contains the OSGi standard dependency directives.
We also see a spring folder. Gemini Blueprint reads the .xml files in this folder and starts a special application context
(BundleContext) containing the beans described in these files.
Figure 17.6. On the left is the interaction with a bank, analogous to the classic Java approach involving a lot of unwanted
potential interaction. On the right is the improved interaction with an exposed automatic teller machine, analogous to a service
exposed using OSGi.
Figure 17.7. The shaded bundles here have a Spring Integration dependency, but the white ones do not.
Chapter 18. Testing
Figure 18.1. The test sends a message on the tripCommands channel and receives the subcommands that were sent by the splitter.
Now a test can verify that the splitter is configured correctly by asserting that the payload of the messages matches the
contents of the original TripCommand.
Figure 18.2. First record the behavior of the mock . Then send a test message to the input channel . After waiting for the
message to come out of the other end , verify that the appropriate operations on the mock have been invoked . Variations on
this recipe work also in more complex cases.