diff --git a/spring-integration-reference/src/endpoint.xml b/spring-integration-reference/src/endpoint.xml index baf5ac52f1..de5a65a2b2 100644 --- a/spring-integration-reference/src/endpoint.xml +++ b/spring-integration-reference/src/endpoint.xml @@ -3,6 +3,13 @@ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> Message Endpoints + + The first part of this chapter covers some background theory and reveals quite a bit about the underlying API + that drives Spring Integration's various messaging components. This information can be helpful if you want to + really understand what's going on behind the scenes. However, if you want to get up and running with the + simplified namespace-based configuration of the various elements, feel free to skip ahead to + for now. + As mentioned in the overview, Message Endpoints are responsible for connecting the various messaging components to channels. Over the next several chapters, you will see a number of different components that consume Messages. Some @@ -10,17 +17,17 @@ , it's easy to send a Message to a Message Channel. However, receiving is a bit more complicated. The main reason is that there are two types of consumers: Polling Consumers and - Event-Driven Consumers. + Event Driven Consumers. - Of the two, Event-Driven Consumers are much simpler. Without any need to manage and schedule a separate poller + Of the two, Event Driven Consumers are much simpler. Without any need to manage and schedule a separate poller thread, they are essentially just listeners with a callback method. When connecting to one of Spring Integration's subscribable Message Channels, this simple option works great. However, when connecting to a buffering, pollable Message Channel, some component has to schedule and manage the polling thread(s). Spring Integration provides two different endpoint implementations to accommodate these two types of consumers. Therefore, the consumers themselves can simply implement the callback interface. When polling is required, the endpoint acts as a "container" for the consumer instance. The benefit is similar to that of using a container for hosting - Message-Driven Beans, but since these consumers are simply Spring-managed Objects running within an + Message Driven Beans, but since these consumers are simply Spring-managed Objects running within an ApplicationContext, it more closely resembles Spring's own MessageListener containers. @@ -47,9 +54,9 @@
- Event-Driven Consumer + Event Driven Consumer - Because it is the simpler of the two, we will cover the Event-Driven Consumer endpoint first. You may recall that + Because it is the simpler of the two, we will cover the Event Driven Consumer endpoint first. You may recall that the SubscribableChannel interface provides a subscribe() method and that the method accepts a MessageHandler parameter (as shown in ): @@ -57,9 +64,9 @@ subscribableChannel.subscribe(messageHandler); Since a handler that is subscribed to a channel does not have to actively poll that channel, this is an - Event-Driven Consumer, and the implementation provided by Spring Integration accepts a + Event Driven Consumer, and the implementation provided by Spring Integration accepts a a SubscribableChannel and a MessageHandler: - SubscribableChannel channel = (SubscribableChannel) context.getBean("exampleSubscribableChannel"); + SubscribableChannel channel = (SubscribableChannel) context.getBean("subscribableChannel"); EventDrivenConsumer consumer = new EventDrivenConsumer(channel, exampleHandler); @@ -70,7 +77,7 @@ EventDrivenConsumer consumer = new EventDrivenConsumer(channel, exampleHandler); Spring Integration also provides a PollingConsumer, and it can be instantiated in the same way except that the channel must implement PollableChannel: - PollableChannel channel = (PollableChannel) context.getBean("examplePollableChannel"); + PollableChannel channel = (PollableChannel) context.getBean("pollableChannel"); PollingConsumer consumer = new PollingConsumer(channel, exampleHandler); @@ -83,12 +90,12 @@ consumer.setTrigger(new IntervalTrigger(30, TimeUnit.SECONDS)); Spring Integration currently provides two implementations of the Trigger interface: IntervalTrigger and CronTrigger. The IntervalTrigger is typically defined with a simple interval (in milliseconds), but - also supports an 'initialDelay' property and a boolean 'fixedRate' property (the default is false - i.e. + also supports an 'initialDelay' property and a boolean 'fixedRate' property (the default is false, i.e. fixed delay): IntervalTrigger trigger = new IntervalTrigger(1000); trigger.setInitialDelay(5000); trigger.setFixedRate(true); - The CronTrigger simply requires the cron expression (see the Javadoc for details): + The CronTrigger simply requires a valid cron expression (see the Javadoc for details): CronTrigger trigger = new CronTrigger("*/10 * * * * MON-FRI"); @@ -99,8 +106,29 @@ PollingConsumer consumer = new PollingConsumer(channel, handler); consumer.setMaxMessagesPerPoll(10); consumer.setReceiveTimeout(5000); - A Polling Consumer may even delegate to a Spring TaskExecutor and - participate in Spring-managed transactions. The following example shows the configuration of both: + + + The 'maxMessagesPerPoll' property specifies the maximum number of messages to receive within a given poll + operation. This means that the poller will continue calling receive() without waiting + until either null is returned or that max is reached. For example, if a poller has a 10 second + interval trigger and a 'maxMessagesPerPoll' setting of 25, and it is polling a channel that has 100 messages + in its queue, all 100 messages can be retrieved within 40 seconds. It grabs 25, waits 10 seconds, grabs the + next 25, and so on. + + + The 'receiveTimeout' property specifies the amount of time the poller should wait if no messages are + available when it invokes the receive operation. For example, consider two options that seem similar on + the surface but are actually quite different: the first has an interval trigger of 5 seconds and a receive + timeout of 50 milliseconds while the second has an interval trigger of 50 milliseconds and a receive timeout + of 5 seconds. The first one may receive a message up to 4950 milliseconds later than it arrived on the channel + (if that message arrived immediately after one of its poll calls returned). On the other hand, the second + configuration will never miss a message by more than 50 milliseconds. The difference is that the second + option requires a thread to wait, but as a result it is able to respond much more quickly to arriving messages. + This technique, known as "long polling", can be used to emulate event-driven behavior on a polled source. + + + A Polling Consumer may also delegate to a Spring TaskExecutor, and it can + be configured to participate in Spring-managed transactions. The following example shows the configuration of both: PollingConsumer consumer = new PollingConsumer(channel, handler); @@ -159,7 +187,7 @@ consumer.setTransactionManager(txManager); If the input channel is a PollableChannel, then the poller configuration is required. Specifically, as mentioned above, the 'trigger' is a required property of the PollingConsumer class. Therefore, if you omit the "poller" sub-element for a Polling Consumer endpoint's configuration, an Exception - will be thrown. However, it is also possible to create top-level pollers in which case only a "ref" is required: + may be thrown. However, it is also possible to create top-level pollers in which case only a "ref" is required: @@ -170,9 +198,9 @@ consumer.setTransactionManager(txManager); ]]> In fact, to simplify the configuration, you can define a global default poller. A single top-level poller within - an ApplicationContext may have the default attribute with a value of "true". In that case, any endpoint with a - PollableChannel for its input-channel that is defined within the same ApplicationContext and has no explicitly - configured 'poller' sub-element will use that default. + an ApplicationContext may have the default attribute with a value of "true". In that case, any + endpoint with a PollableChannel for its input-channel that is defined within the same ApplicationContext and has + no explicitly configured 'poller' sub-element will use that default. @@ -190,7 +218,7 @@ consumer.setTransactionManager(txManager); @@ -216,26 +244,30 @@ consumer.setTransactionManager(txManager); queue-capacity="20" keep-alive-seconds="120"/>]]> If no 'task-executor' is provided, the consumer's handler will be invoked in the caller's thread. Note that the - "caller" is usually the default TaskScheduler (see ). Also, keep in mind that the 'task-executor' attribute can + "caller" is usually the default TaskScheduler + (see ). Also, keep in mind that the 'task-executor' attribute can provide a reference to any implementation of Spring's TaskExecutor interface by specifying the bean name. The thread pool element is simply provided for convenience. - You can also use Polling consumers to emulate event-driven semantics. With a long receive-timeout and a short trigger - interval you can effectively approximate event-driven behavior even for a polled message source. + As mentioned in the background section for Polling Consumers above, you can also configure a Polling Consumer + in such a way as to emulate event-driven behavior. With a long receive-timeout and a short interval-trigger, + you can ensure a very timely reaction to arriving messages even on a polled message source. - A good use case that shows how this approach could be aplied is event-driven files via inbound-channel-adapter where drop of the - file into a directory woudl essentially become an event for that file to be picked up and sent throught the process. - - - - -]]> - Using this approach does not carry much overhead since internally it is nothing more then a timed-wait thread which does not use much of CPU resurces + A good use case that demonstrates how this approach could be applied is event-driven files via Spring + Integration's inbound-channel-adapter in the file namespace where a file dropped + into a directory would essentially become an event. That file will be picked up nearly instantaneously and + sent through the process. + + + + + ]]> + Using this approach does not carry much overhead since internally it is nothing more then a timed-wait thread + which does not require nearly as much CPU resource usage as a thrashing, infinite while loop for example. - - +
\ No newline at end of file