Update docs for 1.0.0

This commit is contained in:
Dave Syer
2011-08-19 12:08:36 -07:00
parent 6752d6f806
commit 006ba6a5ae
3 changed files with 184 additions and 58 deletions

View File

@@ -219,22 +219,26 @@
that exists only within our "spring-rabbit" module since at this point,
RabbitMQ is the only supported implementation.</para>
<para>The central component for managing a connection to the RabbitMQ
broker is the <interfacename>ConnectionFactory</interfacename> interface.
The responsibility of a <interfacename>ConnectionFactory</interfacename>
implementation is to provide an instance of
<classname>com.rabbitmq.client.Connection</classname>. The simplest
implementation we provide is
<classname>SingleConnectionFactory</classname> which establishes a single
connection that can be shared by the application. Sharing of the
connection is possible since the "unit of work" for messaging with AMQP is
actually a "channel" (in some ways, this is similar to the relationship
between a Connection and a Session in JMS). As you can imagine, the
connection instance provides a <methodname>createChannel</methodname>
method. When creating an instance of
<classname>SingleConnectionFactory</classname>, the 'hostname' can be
provided via the constructor. The 'username' and 'password' properties
should be provided as well.</para>
<para>The central component for managing a connection to the
RabbitMQ broker is the
<interfacename>ConnectionFactory</interfacename> interface. The
responsibility of a
<interfacename>ConnectionFactory</interfacename> implementation is
to provide an instance of
<classname>org.springframework.amqp.rabbit.connection.Connection</classname>
which is a wrapper for
<classname>com.rabbitmq.client.Connection</classname>. The
simplest implementation we provide is
<classname>SingleConnectionFactory</classname> which establishes a
single connection that can be shared by the application. Sharing
of the connection is possible since the "unit of work" for
messaging with AMQP is actually a "channel" (in some ways, this is
similar to the relationship between a Connection and a Session in
JMS). As you can imagine, the connection instance provides a
<methodname>createChannel</methodname> method. When creating an
instance of <classname>SingleConnectionFactory</classname>, the
'hostname' can be provided via the constructor. The 'username' and
'password' properties should be provided as well.</para>
<programlisting language="java"><![CDATA[SingleConnectionFactory connectionFactory = new SingleConnectionFactory("somehost");
connectionFactory.setUsername("guest");
@@ -251,29 +255,21 @@ Connection connection = connectionFactory.createConnection();]]></programlisting
<property name="password" value="guest"/>
</bean>]]></programlisting>
<para><note>
There is also a
<classname>CachingConnectionFactory</classname>
implementation, which is superior to the
<classname>SingleConnectionFactory</classname>
in terms of performance and resilience. The
<classname>CachingConnectionFactory</classname>
should be considered the default for most practical usage, and
<classname>SingleConnectionFactory</classname>
as useful for simple tests and maybe as a building block for extending the framework.
</note> A <classname>ConnectionFactory</classname> can be created
quickly and conveniently using the rabbit namespace: <programlisting
language="xml"><![CDATA[<rabbit:connection-factory id="connectionFactory"/>]]></programlisting>
In most cases this will be preferable since the framework can choose the
best defaults for you, and it will always choose a
<para><note> There is also a
<classname>CachingConnectionFactory</classname> implementation,
which is superior to the
<classname>SingleConnectionFactory</classname> in terms of
performance and resilience. The
<classname>CachingConnectionFactory</classname> should be
considered the default for most practical usage, and
<classname>SingleConnectionFactory</classname> as useful for
simple tests and maybe as a building block for extending the
framework. </note> A <classname>ConnectionFactory</classname> can
be created quickly and conveniently using the rabbit namespace:
<programlisting language="xml"><![CDATA[<rabbit:connection-factory
id="connectionFactory"/>]]></programlisting> In most cases this
will be preferable since the framework can choose the best
defaults for you, and it will always choose a
<classname>CachingConnectionFactory</classname>.</para>
</section>
@@ -946,7 +942,7 @@ public class ExampleExternalTransactionAmqpConfiguration {
<para>AMQP transactions only apply to messages and acks sent to the
broker, so when there is a rollback of a Spring transaction and a
message has been received, wheat Spring AMQP has to do is not just
message has been received, what Spring AMQP has to do is not just
rollback the transaction, but also manually reject the message (sort of
a nack, but that's not what the specification calls it). Such messages
(and any that are unacked when a channel is closed or aborts) go to the
@@ -1081,4 +1077,118 @@ public class ExampleExternalTransactionAmqpConfiguration {
</tgroup>
</table></para>
</section>
<section>
<title>Resilience: Recovering from Errors and Broker Failures</title>
<para>Some of the key (and most popular) high-level features that
Spring AMQP provides are to do with recovery and automatic
re-connection in the event of a protocol error or broker failure.
We have seen all the relevant components already in this guide,
but it should help to bring them all together here and call out
the features and recovery scenarios individually.</para>
<para>The most important practical step if you want to take
advantage of these features is to use the
<classname>CachingConnectionFactory</classname>. It is also often
beneficial to use the <classname>RabbitAdmin</classname>
auto-declaration features. In addition, if you care about
guaranteed delivery, you probably also need to use the
<code>channelTransacted</code> flag in
<classname>RabbitTemplate</classname> and
<classname>SimpleMessageListenerContainer</classname> and also the
<code>AcknowledgeMode.AUTO</code> (or manual if you do the acks
yourself) in the
<classname>SimpleMessageListenerContainer</classname>.</para>
<section>
<title>Automatic Declararation of Exchanges, Queues and
Bindings</title>
<para>The <classname>RabbitAdmin</classname> component can
declare exchanges, queues and bindings on startup. It does this
lazily, through a <classname>ConnectionListener</classname>, so
if the broker is not present on startup it doesn't matter. The
first time a <classname>Connection</classname> is useed (e.g. by
sending a message) the listener will fire and the admin features
will be applied. A further benefit of doing the auto
declarations in a listener is that if the connection is dropped
for any reason (e.g. broker death, network glitch, etc.) they
will be applied again the next time they are needed.</para>
</section>
<section>
<title>Failures in Synchronous Operations and Options for Retry</title>
<para>If you lose your connection to the broker in a synchronous
sequence using <classname>RabbitTemplate</classname> (for
instance), then Spring AMQP will throw an
<classname>AmqpException</classname> (usually but not always
<classname>AmqpIOException</classname>). We don't try to hide
the fact that there was a problem, so you have to be able to
catch and respond to the exception. The easiest thing to do if
you suspect that the connection was lost, and it wasn't your
fault, is to simply try the operation again. You can do this
manually, or you could look at using Spring Retry to handle the
retry (imperatively or declaratively).</para>
<para>Spring Retry provides a couple of AOP interceptors and a
great deal of flexibility to specify the parameters of the retry
(number of attempts, exception types, backoff algorithm etc.).
Spring AMQP also provides some convenience factory beans for
creating Spring Retry interceptors in a convenient form for AMQP
use cases, with strongly typed callback interfaces for you to
implement custom recovery logic. See the Javadocs and
properties of
<classname>StatefulRetryOperationsInterceptor</classname> and
<classname>StatelessRetryOperationsInterceptor</classname> for
more detail. Stateless retry is appropriate if there is no
transaction or if a transaction is started inside the retry
callback. Note that stateless retry is simpler to configure and
analyse than stateful retry, but it is not usually appropriate
if there is an ongoing transaction which must be rolled back or
definitely is going to roll back. A dropped connection in the
middle of a transaction should have the same effect as a
rollback, so for reconnection where the transaction is started
higher up uthe stack, stateful retry is usually the best
choice.</para>
</section>
<section>
<title>Message Listeners and the Asynchronous Case</title>
<para>If a <classname>MessageListener</classname> fails because
of a business exception, the exception is handled by the message
listener container and then it goes back to listening for
another message. If the failure is caused by a dropped
conection (not a business exception), then the consumer that is
collecting messages for the listener has to be cancelled and
restarted. The
<classname>SimpleMessageListenerContainer</classname> handles
this seamlessly, and leaves a log to say that the listener is
being restarted. In fact it loops endlessly trying to restart
the consumer, and only if the consumer is very badly behaved
indeed will it give up. One side effect is that if the broker
is down when the container starts, it will just keep trying
until a connection can be established.</para>
<para>Business exception handling, as opposed to protocol errors
and dropped connections, might need more thought and some custom
configuration, especially if transactions and/or container acks
are in use. AMQP has no definition of dead letter behaviour, so
by default a message that is rejected or rolled back because of
a business exception can be redelivered ad infinitum. To put a
limit in the client on the number of re-deliveries your best
choice is a
<classname>StatefulRetryOperationsInterceptor</classname> in the
advice chain of the listener. The interceptor can have a
recovery callback that implements a custom dead letter action:
whatever is appropriate for your particular environment.</para>
</section>
</section>
</chapter>

View File

@@ -39,19 +39,18 @@
<xi:include href="preface.xml"/>
<!--
<part>
<title>Introduction</title>
<partintro>
<para>
This first part of the reference documentation
<link linkend="what-is-spring-amqp">is an overview</link> of
Spring AMQP and the underlying concepts.
This first part of the reference documentation is a
high-level overview of Spring AMQP and the underlying
concepts and some code snippets that qill get you up
and running as quickly as possible.
</para>
</partintro>
<xi:include href="quick-tour.xml"/>
</part>
-->
<part>
<title>Reference</title>

View File

@@ -8,19 +8,16 @@
<title>Introduction</title>
<para>The <ulink url="http://springsource.org/spring-integration">Spring Integration</ulink> project
will include AMQP Channel Adapters and Gateways that build upon the Spring AMQP project as soon
as the Spring AMQP project has a GA release. For now, those adapters are under development in the
Spring Integration <ulink url="https://src.springsource.org/svn/spring-integration/sandbox/spring-integration-amqp/">sandbox</ulink>.
includes AMQP Channel Adapters and Gateways that build upon the Spring AMQP project. Those adapters are developed and released in the
Spring Integration project.
In Spring Integration, "Channel Adapters" are unidirectional (one-way) whereas "Gateways" are
bidirectional (request-reply). Ultimately, we will be providing an inbound-channel-adapter,
outbound-channel-adapter, inbound-gateway, and outbound-gateway. As of the time of the Spring AMQP 1.0
Milestone 1 release, the 2 Channel Adapters are available. As mentioned, they are still in the "sandbox"
and as such are subject to change and should not be depended upon in a production environment. That said,
if you check out the project, you should be able to build it with Maven and experiment for yourself.</para>
bidirectional (request-reply). We provide an inbound-channel-adapter,
outbound-channel-adapter, inbound-gateway, and outbound-gateway.</para>
<para>When the AMQP adapters are part of an official Spring Integration release, the documentation
will be available as part of the Spring Integration distribution. In the meantime, we will just
provide a quick overview of the current state of that development here.</para>
<para>Since the AMQP adapters are part of the Spring Integration
release, the documentation will be available as part of the Spring
Integration distribution. As a taster, we just provide a quick
overview of the main features here.</para>
</section>
<section>
@@ -48,13 +45,33 @@
<section>
<title>Inbound Gateway</title>
<para>Coming Soon</para>
<para>To receive an AMQP Message from a Queue, and respond to an
Exchange, configure an &lt;inbound-gateway&gt;. A
'routing-key' may optionally be provided in addition to the
exchange name.</para>
<programlisting language="xml"><![CDATA[<amqp:inbound-gateway input-channel="fromAMQP"
output-channel="toAMQP"
exchange-name="some.exchange"
routing-key="foo"
queue-name="some.queue"
amqp-template="rabbitTemplate"/>]]></programlisting>
</section>
<section>
<title>Outbound Gateway</title>
<para>Coming Soon</para>
<para>To send AMQP Messages to an Exchange and receive back a
response from a remote client, configure an
&lt;outbound-gateway&gt;. A 'routing-key' may optionally be
provided in addition to the exchange name.</para>
<programlisting language="xml"><![CDATA[<amqp:outbound-gateway input-channel="toAMQP"
output-channel="fromAMQP"
exchange-name="some.exchange"
routing-key="foo"
amqp-template="rabbitTemplate"/>]]></programlisting>
</section>
</chapter>