This is a significant update to the build system, including the changes listed below. README.md has been updated with instructions on the most important day-to-day commands. - Eliminate buildSrc submodule In favor of using the new bundlor and docbook-reference plugins. The net effect is a large reduction in number of lines of build code. Common docbook resources, stylesheets, etc are stored directly in the docbook plugin. This means that --recursive is no longer required when cloning and there will never be a need to use `git submodule` commands. README files have been updated to reflect. Use of the new bundlor plugin also means the removal of template.mf files from the source tree in favor of an inline approach. See build.gradle for details. Bundlor 'import templates' are built up programmatically and kept physically close to gradle dependency declarations, leading to more convenience when changing these values and hopefully fewer errors / version inconsistencies over time. Certain tests depended on the presence of template.mf files, all of which have recently been removed from the source tree in favor of the new bundlor plugin which allows for inlining bundlor configuration within the Gradle build script. These tests now create temp files using the java.io.File API instead. - Upgrade to Gradle 1.0-milestone-6 The m6 release is significantly faster when resolving dependencies and has a number of valuable new features over the earlier m3 version. Review the release notes for Gradle 1.0-milestone-6 online for full details. - Switch to repo.springsource.org repository Previously the project build declared as many repositories as necessary to resolve all project dependencies. Now depending on a single 'virtual repository' defined within the SpringSource Artifactory instance at http://repo.springsource.org. Currently, the virtual repository in use is 'libs-milestone', which allows for the resolution of all "milestone-or-better" versions of all S2 and third-party dependencies. Should snapshot dependencies become required, this value may be changed from 'libs-milestone' to 'libs-snapshot'. To build only against GA releases, change the value to 'libs-release'. - New build plan(s) Spring Integration build plans have been updated to use the Artifactory Bamboo plugin and publish to repo.springsource.org. Build plans have names like 2.1.x to reflect the version under development, not necessarily the name of the branch, as this may change over time and across major releases. - Improve release process As mentioned above, Spring Integration will now use the Artifactory Bamboo plugin to publish releases and also use Artifactory's support for pushing builds directly into Maven Central via oss.sonatype.org. Generate poms that contain all necessary fields for onboarding at Maven central (scm, developers, organization, licenses, etc). Generate -source and -javadoc poms to comply with Maven Central onboarding rules (and for general good practice anyway). Generation of PGP signatures, sha1 and md5 checksums are all handled automatically by Artifactory. These are also requirements for automated entry into Maven Central. - Remove source-level pom generation Automatic generation of Maven poms suitable for use in building Spring Integration is no longer supported. Generation and publication of poms for the purpose of dependency management remains supported. Sonar support has to date depended on these poms, but will be switched over to use the Gradle Sonar plugin shortly. - Eliminate docs subproject Move docs/src to the root of the project and eliminate docs as a formal subproject. This simplifies the build in a number of ways, including removing the need for distinguishing between 'subprojects' and 'javaprojects' as well as allowing users to build both 'api' and 'reference' docs without qualifying with a ':docs' prefix. Also rename the src/info directory to src/dist to better reflect that these files are packaged with the distribution. For example, the readme.txt there is really the distribution readme, distinct from the README.md at the root of the project which is for building from source, etc.
410 lines
25 KiB
XML
410 lines
25 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="gateway"
|
||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||
<title>Messaging Gateways</title>
|
||
<para>
|
||
The primary purpose of a Gateway is to hide the messaging API provided by
|
||
Spring Integration. It allows your application's business logic to be completely
|
||
unaware of the Spring Integration API and using a generic Gateway, your code
|
||
interacts instead with a simple interface, only.
|
||
</para>
|
||
<section id="gateway-proxy">
|
||
<title>Enter the GatewayProxyFactoryBean</title>
|
||
<para>
|
||
As mentioned above, it would be great to have no dependency on the Spring
|
||
Integration API at all - including the gateway class. For that reason, Spring
|
||
Integration provides the <classname>GatewayProxyFactoryBean</classname> that
|
||
generates a proxy for any interface and internally invokes the gateway
|
||
methods shown below. Using dependency injection you can then expose the interface
|
||
to your business methods.
|
||
</para>
|
||
<para>
|
||
Here is an example of an interface that can be used to interact with Spring
|
||
Integration:
|
||
</para>
|
||
|
||
<programlisting language="java"><![CDATA[package org.cafeteria;
|
||
|
||
public interface Cafe {
|
||
|
||
void placeOrder(Order order);
|
||
|
||
}]]></programlisting>
|
||
|
||
</section>
|
||
<section id="gateway-namespace">
|
||
<title>Gateway XML Namespace Support</title>
|
||
<para>
|
||
Namespace support is also
|
||
provided which allows you to configure such an interface as a service as demonstrated by the following example.
|
||
</para>
|
||
<programlisting language="xml"><![CDATA[<int:gateway id="cafeService"
|
||
service-interface="org.cafeteria.Cafe"
|
||
default-request-channel="requestChannel"
|
||
default-reply-channel="replyChannel"/>]]></programlisting>
|
||
<para>
|
||
With this configuration defined, the "cafeService" can now be injected into other beans, and the code that invokes the methods on that
|
||
proxied instance of the Cafe interface has no awareness of the Spring Integration API. The general
|
||
approach is similar to that of Spring Remoting (RMI, HttpInvoker, etc.). See the "Samples" Appendix for
|
||
an example that uses this "gateway" element (in the Cafe demo).
|
||
</para>
|
||
</section>
|
||
<section id="gateway-default-reply-channel">
|
||
<title>Setting the Default Reply Channel</title>
|
||
<para>
|
||
Typically you don't have to specify the <code>default-reply-channel</code>,
|
||
since a Gateway will auto-create a temporary, anonymous reply channel,
|
||
where it will listen for the reply. However, there are some cases which
|
||
may prompt you to define a <code>default-reply-channel</code> (or <code>reply-channel</code>
|
||
with adapter gateways such as HTTP, JMS, etc.).
|
||
</para>
|
||
<para>
|
||
For some background, we'll quickly discuss some of the inner-workings of the Gateway.
|
||
A Gateway will create a temporary point-to-point reply channel which is anonymous and is added
|
||
to the Message Headers with the name <code>replyChannel</code>.
|
||
When providing an explicit <code>default-reply-channel</code> (<code>reply-channel</code> with remote adapter gateways),
|
||
you have the option to point to a publish-subscribe channel, which is so named because you can add more than one subscriber to it.
|
||
Internally Spring Integration will create a Bridge between the temporary <code>replyChannel</code> and the explicitly defined
|
||
<code>default-reply-channel</code>.
|
||
</para>
|
||
<para>
|
||
So let's say you want your reply to go not only to the gateway, but also to some other consumer. In this case you
|
||
would want two things: <emphasis>a) a named channel you can subscribe to and b) that channel is a publish-subscribe-channel.</emphasis>
|
||
The default strategy used by the gateway will not satisfy those needs, because the reply channel added to the header is anonymous and
|
||
point-to-point. This means that no other subscriber can get a handle to it and even if it could, the channel
|
||
has point-to-point behavior such that only one subscriber would get the Message. So by defining a <code>default-reply-channel</code>
|
||
you can point to a channel of your choosing, which in this case would be a <code>publish-subscribe-channel</code>.
|
||
The Gateway would create a bridge from it to the temporary, anonymous reply channel that is stored in the header.
|
||
</para>
|
||
<para>
|
||
Another case where you might want to provide a reply channel explicitly is for monitoring or auditing via an interceptor
|
||
(e.g., wiretap). You need a named channel in order to configure a Channel Interceptor.
|
||
</para>
|
||
</section>
|
||
<section id="gateway-configuration-annotations">
|
||
<title>Gateway Configuration with Annotations and/or XML</title>
|
||
<para>
|
||
The reason that the attributes on the 'gateway' element are named 'default-request-channel' and
|
||
'default-reply-channel' is that you may also provide per-method channel references by using the
|
||
<classname>@Gateway</classname> annotation.
|
||
</para>
|
||
|
||
<programlisting language="java"><![CDATA[ public interface Cafe {
|
||
|
||
@Gateway(requestChannel="orders")
|
||
void placeOrder(Order order);
|
||
|
||
}]]></programlisting>
|
||
<para>
|
||
You may alternatively provide such content in <code>method</code> sub-elements if you prefer XML configuration (see the next paragraph).
|
||
</para>
|
||
<para>
|
||
It is also possible to pass values to be interpreted as Message headers on the Message
|
||
that is created and sent to the request channel by using the @Header annotation:
|
||
</para>
|
||
<programlisting language="java"><![CDATA[ public interface FileWriter {
|
||
|
||
@Gateway(requestChannel="filesOut")
|
||
void write(byte[] content, @Header(FileHeaders.FILENAME) String filename);
|
||
|
||
}]]></programlisting>
|
||
|
||
<para>
|
||
If you prefer the XML approach of configuring Gateway methods, you can provide <emphasis>method</emphasis> sub-elements
|
||
to the gateway configuration.
|
||
</para>
|
||
|
||
<programlisting language="xml"><![CDATA[<int:gateway id="myGateway" service-interface="org.foo.bar.TestGateway"
|
||
default-request-channel="inputC">
|
||
<int:method name="echo" request-channel="inputA" reply-timeout="2" request-timeout="200"/>
|
||
<int:method name="echoUpperCase" request-channel="inputB"/>
|
||
<int:method name="echoViaDefault"/>
|
||
</int:gateway>]]></programlisting>
|
||
|
||
<para>
|
||
You can also provide individual headers per method invocation via XML.
|
||
This could be very useful if the headers you want to set are static in nature and you don't want
|
||
to embed them in the gateway's method signature via <classname>@Header</classname> annotations.
|
||
For example, in the Loan Broker example we want to influence how aggregation of the Loan quotes
|
||
will be done based on what type of request was initiated (single quote or all quotes). Determining the
|
||
type of the request by evaluating what gateway method was invoked, although possible, would
|
||
violate the separation of concerns paradigm (the method is a java artifact), but expressing your
|
||
intention (meta information) via Message headers is natural in a Messaging architecture.
|
||
</para>
|
||
|
||
<programlisting language="xml"><![CDATA[<int:gateway id="loanBrokerGateway"
|
||
service-interface="org.springframework.integration.loanbroker.LoanBrokerGateway">
|
||
<int:method name="getLoanQuote" request-channel="loanBrokerPreProcessingChannel">
|
||
<int:header name="RESPONSE_TYPE" value="BEST"/>
|
||
</int:method>
|
||
<int:method name="getAllLoanQuotes" request-channel="loanBrokerPreProcessingChannel">
|
||
<int:header name="RESPONSE_TYPE" value="ALL"/>
|
||
</int:method>
|
||
</int:gateway>]]></programlisting>
|
||
<para>
|
||
In the above case you can clearly see how a different value will be set for the 'RESPONSE_TYPE'
|
||
header based on the gateway's method.
|
||
</para>
|
||
|
||
</section>
|
||
<section id="gateway-calling-no-argument-methods">
|
||
<title>Invoking No-Argument Methods</title>
|
||
<para>
|
||
When invoking methods on a Gateway interface that do not have any arguments,
|
||
the default behavior is to <emphasis>receive</emphasis> a <code>Message</code> from a
|
||
<interfacename>PollableChannel</interfacename>.
|
||
</para>
|
||
<para>
|
||
At times however, you may want to trigger no-argument methods so that
|
||
you can in fact interact with other components downstream that do not require
|
||
user-provided parameters, e.g. triggering no-argument SQL calls or Stored
|
||
Procedures.
|
||
</para>
|
||
<para>
|
||
In order to achieve <emphasis>send-and-receive</emphasis> semantics, you must provide a payload.
|
||
In order to generate a payload, method parameters on the interface are
|
||
not necessary. You can either use the <code>@Payload</code> annotation
|
||
or the <code>payload-expression</code> attribute in XML on the <code>method</code>
|
||
sub-element. Below please find a few examples of what the payloads could be:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>a literal string</listitem>
|
||
<listitem>#method (for the method name)</listitem>
|
||
<listitem>new java.util.Date()</listitem>
|
||
<listitem>@someBean.someMethod()'s return value</listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
Here is an example using the <code>@Payload</code> annotation:
|
||
</para>
|
||
<programlisting language="xml"><![CDATA[public interface Cafe {
|
||
|
||
@Payload("new java.util.Date()")
|
||
List<Order> retrieveOpenOrders();
|
||
|
||
}]]></programlisting>
|
||
<para>
|
||
If a method has no argument and no return value, but does contain a
|
||
payload expression, it will be treated as a <emphasis>send-only</emphasis>
|
||
operation.
|
||
</para>
|
||
</section>
|
||
|
||
<section id="gateway-error-handling">
|
||
<title>Error Handling </title>
|
||
<para>
|
||
|
||
Of course, the Gateway invocation might result in errors.
|
||
By default any error that has occurred downstream will be re-thrown as a
|
||
<classname>MessagingException</classname> (RuntimeException)
|
||
upon the Gateway's method invocation. However there are times when you may want
|
||
to simply log the error rather than propagating it, or you may want to treat an
|
||
Exception as a valid reply, by mapping it to a Message that will conform to some
|
||
"error message" contract that the caller understands. To accomplish this, our
|
||
Gateway provides support for a Message Channel dedicated to the errors via the
|
||
<emphasis>error-channel</emphasis> attribute. In the example below, you can see
|
||
that a 'transformer' is used to create a reply Message from the Exception.
|
||
</para>
|
||
|
||
<programlisting language="xml"><![CDATA[<int:gateway id="sampleGateway"
|
||
default-request-channel="gatewayChannel"
|
||
service-interface="foo.bar.SimpleGateway"
|
||
error-channel="exceptionTransformationChannel"/>
|
||
|
||
<int:transformer input-channel="exceptionTransformationChannel"
|
||
ref="exceptionTransformer" method="createErrorResponse"/>
|
||
]]></programlisting>
|
||
<para>
|
||
The <emphasis>exceptionTransformer</emphasis> could be a simple POJO that
|
||
knows how to create the expected error response objects. That would then be
|
||
the payload that is sent back to the caller. Obviously, you could do many
|
||
more elaborate things in such an "error flow" if necessary. It might involve
|
||
routers (including Spring Integration's ErrorMessageExceptionTypeRouter),
|
||
filters, and so on. Most of the time, a simple 'transformer' should be sufficient,
|
||
however.
|
||
</para>
|
||
<para>
|
||
Alternatively, you might want to only log the Exception (or send it somewhere
|
||
asynchronously). If you provide a one-way flow, then nothing would be sent
|
||
back to the caller. In the case that you want to completely suppress Exceptions,
|
||
you can provide a reference to the global "nullChannel" (essentially a /dev/null
|
||
approach). Finally, as mentioned above, if no "error-channel" is defined at all,
|
||
then the Exceptions will propagate as usual.
|
||
</para>
|
||
<para>
|
||
<important>
|
||
Exposing the messaging system via simple POJI Gateways obviously provides benefits, but "hiding" the reality
|
||
of the underlying messaging system does come at a price so there are certain things you should consider.
|
||
|
||
We want our Java method to return as quickly as possible and not hang for an indefinite amount of time while
|
||
the caller is waiting on it to return (void, return value, or a thrown Exception). When regular methods are
|
||
used as a proxies in front of the Messaging system, we have to take into account the potentially asynchronous
|
||
nature of the underlying messaging. This means that there might
|
||
be a chance that a Message that was initiated by a Gateway could be dropped by a Filter, thus never reaching a
|
||
component that is responsible for producing a reply. Some Service Activator method might result in an Exception,
|
||
thus providing no reply (as we don't generate Null messages). So as you can see there are multiple scenarios
|
||
where a reply message might not be coming. That is perfectly natural in messaging systems. However think about the
|
||
implication on the gateway method. The Gateway's method input arguments were incorporated into a Message and
|
||
sent downstream. The reply Message would be converted to a return value of the Gateway's method. So you might want
|
||
to ensure that for each Gateway call there will always be a reply Message.
|
||
Otherwise, your Gateway method might never return and will hang indefinitely.
|
||
One of the ways of handling this situation is via an Asynchronous Gateway (explained later in this section). Another way of handling it is to explicitly set the reply-timeout attribute. That way, the gateway will not hang any longer than the time specified by the reply-timeout and will return 'null' if that timeout does elapse. Finally, you might want to consider setting downstream flags such as 'requires-reply' on
|
||
a service-activator or 'throw-exceptions-on-rejection' on a filter. These options will be discussed in more detail in the final section
|
||
of this chapter.
|
||
</important>
|
||
</para>
|
||
</section>
|
||
<section id="async-gateway">
|
||
<title>Asynchronous Gateway</title>
|
||
<para>
|
||
As a pattern the Messaging Gateway is a very nice way to hide messaging-specific code while still exposing the full capabilities of the
|
||
messaging system. As you've seen, the <classname>GatewayProxyFactoryBean</classname> provides a convenient way to expose a Proxy over a service-interface
|
||
thus giving you POJO-based access to a messaging system (based on objects in your own domain, or primitives/Strings, etc). But when a
|
||
gateway is exposed via simple POJO methods which return values it does imply that for each Request message (generated when the method is invoked)
|
||
there must be a Reply message (generated when the method has returned). Since Messaging systems naturally are asynchronous you may not always be
|
||
able to guarantee the contract where <emphasis>"for each request there will always be be a reply"</emphasis>.
|
||
With Spring Integration 2.0 we are introducing support for an <emphasis>Asynchronous Gateway</emphasis> which is a convenient way to initiate
|
||
flows where you may not know if a reply is expected or how long will it take for replies to arrive.
|
||
</para>
|
||
<para>
|
||
A natural way to handle these types of scenarios in Java would be relying upon <emphasis>java.util.concurrent.Future</emphasis> instances, and
|
||
that is exactly what Spring Integration uses to support an <emphasis>Asynchronous Gateway</emphasis>.
|
||
</para>
|
||
<para>
|
||
From the XML configuration, there is nothing different and you still define <emphasis>Asynchronous Gateway</emphasis> the same way as a regular Gateway.
|
||
</para>
|
||
<programlisting language="xml"><![CDATA[<int:gateway id="mathService"
|
||
service-interface="org.springframework.integration.sample.gateway.futures.MathServiceGateway"
|
||
default-request-channel="requestChannel"/>]]></programlisting>
|
||
<para>
|
||
However the Gateway Interface (service-interface) is a bit different.
|
||
</para>
|
||
<programlisting language="java">public interface MathServiceGateway {
|
||
Future<Integer> multiplyByTwo(int i);
|
||
}</programlisting>
|
||
|
||
<para>
|
||
As you can see from the example above the return type for the gateway method is a <classname>Future</classname>. When
|
||
<classname>GatewayProxyFactoryBean</classname> sees that the
|
||
return type of the gateway method is a <classname>Future</classname>, it immediately switches to the async mode by utilizing
|
||
an <classname>AsyncTaskExecutor</classname>. That is all. The call to such a method always returns immediately with a <classname>Future</classname> instance.
|
||
Then, you can interact with the <classname>Future</classname> at your own pace to get the result, cancel, etc. And, as with
|
||
any other use of Future instances, calling get() may reveal a timeout, an execution exception, and so on.
|
||
<programlisting language="java">MathServiceGateway mathService = ac.getBean("mathService", MathServiceGateway.class);
|
||
Future<Integer> result = mathService.multiplyByTwo(number);
|
||
// do something else here since the reply might take a moment
|
||
int finalResult = result.get(1000, TimeUnit.SECONDS);</programlisting>
|
||
For a more detailed example, please refer to the <emphasis>async-gateway</emphasis> sample distributed within the Spring Integration samples.
|
||
</para>
|
||
|
||
<para><emphasis>Asynchronous Gateway and AsyncTaskExecutor</emphasis></para>
|
||
<para>
|
||
By default <classname>GatewayProxyFactoryBean</classname> uses <classname>org.springframework.core.task.SimpleAsyncTaskExecutor</classname>
|
||
when submitting internal <classname>AsyncInvocationTask</classname> instances for any gateway method whose
|
||
return type is <classname>Future.class</classname>. However the <literal>async-executor</literal> attribute in the
|
||
<literal><gateway/></literal> element's configuration allows you to provide a reference to any implementation of
|
||
<classname>java.util.concurrent.Executor</classname> available within the Spring application context.
|
||
</para>
|
||
</section>
|
||
<section>
|
||
<title>Gateway behavior when no response arrives</title>
|
||
<para>
|
||
As it was explained earlier, the Gateway provides a convenient way of interacting with a Messaging system via POJO method
|
||
invocations, but realizing that a typical method invocation, which is generally expected to always return (even with an Exception),
|
||
might not always map one-to-one to message exchanges (e.g., a reply message might not arrive - which is equivalent to a
|
||
method not returning). It is important to go over several scenarios especially in the Sync Gateway case and understand
|
||
the default behavior of the Gateway and how to deal with these scenarios to make the Sync Gateway behavior more
|
||
predictable regardless of the outcome of the message flow that was initialed from such Gateway.
|
||
</para>
|
||
<para>
|
||
There are certain attributes that could be configured to make Sync Gateway behavior more predictable,
|
||
but some of them might not always work as you might have expected. One of them is <emphasis>reply-timeout</emphasis>.
|
||
So, lets look at the <emphasis>reply-timeout</emphasis> attribute and see how it can/can't influence the behavior
|
||
of the Sync Gateway in various scenarios. We will look at single-threaded scenario
|
||
(all components downstream are connected via Direct Channel) and multi-threaded scenarios
|
||
(e.g., somewhere downstream you may have Pollable or Executor Channel which breaks single-thread boundary)
|
||
</para>
|
||
<para>
|
||
<emphasis>Long running process downstream</emphasis>
|
||
</para>
|
||
<para>
|
||
<emphasis>Sync Gateway - single-threaded</emphasis>.
|
||
If a component downstream is still running (e.g., infinite loop or a very slow service), then setting a <emphasis>reply-timeout</emphasis>
|
||
has no effect and the Gateway method call will not return until such downstream service exits (via return or exception).
|
||
<emphasis>Sync Gateway - multi-threaded</emphasis>.
|
||
If a component downstream is still running (e.g., infinite loop or a very slow service), in a multi-threaded message
|
||
flow setting the <emphasis>reply-timeout</emphasis> will have an effect by allowing gateway method invocation to
|
||
return once the timeout has been reached, since the <classname>GatewayProxyFactoryBean</classname> will simply
|
||
poll on the reply channel waiting for a message until the timeout expires. However it could result in a 'null' return
|
||
from the Gateway method if the timeout has been reached before the actual reply was produced. It is also important to understand that
|
||
the reply message (if produced) will be sent to a reply channel after the Gateway method invocation might have returned, so you must be aware of that and design your flow with this in mind.
|
||
</para>
|
||
<para>
|
||
<emphasis>Downstream component returns 'null'</emphasis>
|
||
</para>
|
||
<para>
|
||
<emphasis>Sync Gateway - single-threaded</emphasis>.
|
||
If a component downstream returns 'null' and no <emphasis>reply-timeout</emphasis> has been configured, the Gateway
|
||
method call will hang indefinitely unless: a) a <emphasis>reply-timeout</emphasis> has been configured or b) the
|
||
<emphasis>requires-reply</emphasis> attribute has been set on the downstream component (e.g., service-activator)
|
||
that might return 'null'. In this case, an Exception would be thrown and propagated to the Gateway.
|
||
<emphasis>Sync Gateway - multi-threaded</emphasis>. Behavior is the same as above.
|
||
</para>
|
||
<para>
|
||
<emphasis>Downstream component return signature is 'void' while Gateway method signature is non-void</emphasis>
|
||
</para>
|
||
<para>
|
||
<emphasis>Sync Gateway - single-threaded</emphasis>.
|
||
If a component downstream returns 'void' and no <emphasis>reply-timeout</emphasis> has been configured,
|
||
the Gateway method call will hang indefinitely unless a <emphasis>reply-timeout</emphasis> has been configured
|
||
<emphasis>Sync Gateway - multi-threaded</emphasis> Behavior is the same as above.
|
||
</para>
|
||
<para>
|
||
<emphasis>Downstream component results in Runtime Exception (regardless of the method signature)</emphasis>
|
||
</para>
|
||
<para>
|
||
<emphasis>Sync Gateway - single-threaded</emphasis>.
|
||
If a component downstream throws a Runtime Exception, such exception will be propagated via an Error Message back to
|
||
the gateway and re-thrown.
|
||
<emphasis>Sync Gateway - multi-threaded</emphasis> Behavior is the same as above.
|
||
</para>
|
||
<para>
|
||
<important>
|
||
It is also important to understand that by default <emphasis>reply-timeout</emphasis> is unbounded* which means that
|
||
if not explicitly set there are several scenarios (described above) where your Gateway method invocation might
|
||
hang indefinitely. So, make sure you analyze your flow and if there is even a remote possibility of one of these
|
||
scenarios to occur, set the <emphasis>reply-timeout</emphasis> attribute to a 'safe' value or, even better,
|
||
set the <emphasis>requires-reply</emphasis> attribute of the downstream component to 'true' to ensure a timely response
|
||
as produced by the throwing of an Exception as soon as that downstream component does return null internally.
|
||
But also, realize that there are some scenarios (see the very first one)
|
||
where <emphasis>reply-timeout</emphasis> will not help. That means it is also important to analyze your message
|
||
flow and decide when to use a Sync Gateway vs an Async Gateway. As you've seen the latter case is simply a matter of
|
||
defining Gateway methods that return Future instances. Then, you are guaranteed to receive that return value, and
|
||
you will have more granular control over the results of the invocation.
|
||
<para>
|
||
Also, when dealing with a Router you should remember that setting the <emphasis>resolution-required</emphasis> attribute to 'true'
|
||
will result in an Exception thrown by the router if it can not resolve a particular channel. Likewise, when dealing with a Filter,
|
||
you can set the <emphasis>throw-exception-on-rejection</emphasis> attribute. In both of these cases, the resulting flow will
|
||
behave like that containing a service-activator with the 'requires-reply' attribute. In other words, it will help to ensure
|
||
a timely response from the Gateway method invocation.
|
||
</para>
|
||
<para>
|
||
<note>
|
||
<para>
|
||
* <emphasis>reply-timeout</emphasis> is unbounded for <emphasis><gateway/></emphasis>
|
||
elements (created by the GatewayProxyFactoryBean). Inbound gateways for external integration
|
||
(ws, http, etc.) share many characteristics and attributes with these gateways. However,
|
||
for those inbound gateways, the default <emphasis>reply-timeout</emphasis> is 1000
|
||
milliseconds (1 second). If a downstream async handoff is made to another thread, you may need to
|
||
increase this attribute to allow enough time for the flow to complete before the
|
||
gateway times out.
|
||
</para>
|
||
</note>
|
||
</para>
|
||
</important>
|
||
</para>
|
||
</section>
|
||
|
||
</section>
|