blob: 0918245454b408cd38153abb3e895cb2cf616e3c [file] [log] [blame]
= Spring RabbitMQ Component
:doctitle: Spring RabbitMQ
:shortname: spring-rabbitmq
:artifactid: camel-spring-rabbitmq
:description: Send and receive messages from RabbitMQ using Spring RabbitMQ client.
:since: 3.8
:supportlevel: Stable
:tabs-sync-option:
:component-header: Both producer and consumer are supported
//Manually maintained attributes
:group: Spring
:camel-spring-boot-name: spring-rabbitmq
*Since Camel {since}*
*{component-header}*
The Spring RabbitMQ component allows you to produce and consume messages from
http://www.rabbitmq.com/[RabbitMQ] instances. Using the Spring RabbitMQ
client.
Maven users will need to add the following dependency to their `pom.xml`
for this component:
[source,xml]
----
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-rabbitmq</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
----
== URI format
----
spring-rabbitmq:exchangeName?[options]
----
The exchange name determines the exchange to which the produced
messages will be sent to. In the case of consumers, the exchange name
determines the exchange the queue will be bound to.
// component-configure options: START
// component-configure options: END
// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
// component options: END
// endpoint options: START
// endpoint options: END
// component headers: START
include::partial$component-endpoint-headers.adoc[]
// component headers: END
== Using a connection factory
To connect to RabbitMQ you need to setup a `ConnectionFactory` (same as with JMS) with the login details such as:
TIP: It is recommended to use `CachingConnectionFactory` from spring-rabbit as it comes with connection pooling out of the box.
[source,xml]
----
<bean id="rabbitConnectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
<property name="uri" value="amqp://lolcalhost:5672"/>
</bean>
----
The `ConnectionFactory` is auto-detected by default, so you can just do
[source,xml]
----
<camelContext>
<route>
<from uri="direct:cheese"/>
<to uri="spring-rabbitmq:foo?routingKey=cheese"/>
</route>
</camelContext>
----
== Default Exchange Name
To use default exchange name (which would be an empty exchange name in RabbitMQ) then you should use `default` as name
in the endpoint uri, such as:
[source,java]
----
to("spring-rabbitmq:default?routingKey=foo")
----
== Auto declare exchanges, queues and bindings
Before you can send or receive messages from RabbitMQ, then exchanges, queues and bindings must be setup first.
In development mode it may be desirable to let Camel automatic do this.
You can enable this by setting `autoDeclare=true` on the `SpringRabbitMQComponent`.
Then Spring RabbitMQ will automatic necessary declare the elements and setup the binding between the exchange, queue and routing keys.
The elements can be configured using the multi-valued `args` option.
For example to specify the queue as durable and exclusive, you can configure the endpoint uri with `arg.queue.durable=true&arg.queue.exclusive=true`.
*Exchanges*
[width="100%",cols="10%,10%,70%,10%",options="header",]
|=====================================================================
|Option |Type |Description|Default
| autoDelete | boolean | True if the server should delete the exchange when it is no longer in use (if all bindings are deleted). | false
| durable | boolean | A durable exchange will survive a server restart. | true
|=====================================================================
You can also configure any additional `x-` arguments.
See details in the RabbitMQ documentation.
*Queues*
[width="100%",cols="10%,10%,70%,10%",options="header",]
|=====================================================================
|Option |Type |Description|Default
| autoDelete | boolean | True if the server should delete the exchange when it is no longer in use (if all bindings are deleted). | false
| durable | boolean | A durable queue will survive a server restart. | false
| exclusive | boolean | Whether the queue is exclusive | false
| x-dead-letter-exchange | String | The name of the dead letter exchange. If none configured then the component configured value is used. |
| x-dead-letter-routing-key | String | The routing key for the dead letter exchange. If none configured then the component configured value is used. |
|=====================================================================
You can also configure any additional `x-` arguments, such as the message time to live, via `x-message-ttl`, and many others.
See details in the RabbitMQ documentation.
== Mapping from Camel to RabbitMQ
The message body is mapped from Camel Message body to a `byte[]` which is the type that RabbitMQ uses for message body.
Camel wil use its type converter to convert the message body to byte array.
Spring Rabbit comes out of the box with support for mapping Java serialized objects but Camel Spring RabbitMQ
does *not* support this due to security vulnerabilities and using Java objects is a bad design as it enforces strong coupling.
Custom message headers is mapped from Camel Message headers to RabbitMQ headers. This behaviour can be customized by configuring
a new implementation of `HeaderFilterStrategy` on the Camel component.
== Request / Reply
Request and reply messaging is supported using https://www.rabbitmq.com/direct-reply-to.html[RabbitMQ direct reply-to].
The example below will do request/reply, where the message is sent via the cheese exchange name and routing key _foo.bar_,
which is being consumed by the 2nd Camel route, that prepends the message with `Hello `, and then sends back the message.
So if we send `World` as message body to _direct:start_ then, we will se the message being logged
- log:request => World
- log:input => World
- log:response => Hello World
[source,java]
----
from("direct:start")
.to("log:request")
.to(ExchangePattern.InOut, "spring-rabbitmq:cheese?routingKey=foo.bar")
.to("log:response");
from("spring-rabbitmq:cheese?queues=myqueue&routingKey=foo.bar")
.to("log:input")
.transform(body().prepend("Hello "));
----
== Reuse endpoint and send to different destinations computed at runtime
If you need to send messages to a lot of different RabbitMQ exchanges, it
makes sense to reuse a endpoint and specify the real destination in
a message header. This allows Camel to reuse the same endpoint, but send
to different exchanges. This greatly reduces the number of endpoints
created and economizes on memory and thread resources.
TIP: Using xref:eips:toD-eip.adoc[toD] is easier than specifying the dynamic destination with headers
You can specify using the following headers:
[width="100%",cols="10%,10%,80%",options="header",]
|=====================================================================
|Header |Type |Description
|`CamelSpringRabbitmqExchangeOverrideName` |`String` |The exchange name.
|`CamelSpringRabbitmqRoutingOverrideKey` |`String` |The routing key.
|=====================================================================
For example, the following route shows how you can compute a destination
at run time and use it to override the exchange appearing in the endpoint
URL:
[source,java]
----
from("file://inbox")
.to("bean:computeDestination")
.to("spring-rabbitmq:dummy");
----
The exchange name, `dummy`, is just a placeholder. It must be provided as
part of the RabbitMQ endpoint URL, but it will be ignored in this example.
In the `computeDestination` bean, specify the real destination by
setting the `CamelRabbitmqExchangeOverrideName` header as follows:
[source,java]
----
public void setExchangeHeader(Exchange exchange) {
String region = ....
exchange.getIn().setHeader("CamelSpringRabbitmqExchangeOverrideName", "order-" + region);
}
----
Then Camel will read this header and use it as the exchange name instead
of the one configured on the endpoint. So, in this example Camel sends
the message to `spring-rabbitmq:order-emea`, assuming the `region` value was `emea`.
Keep in mind that the producer removes both `CamelSpringRabbitmqExchangeOverrideName` and `CamelSpringRabbitmqRoutingOverrideKey`
headers from the exchange and do not propagate them to the created Rabbitmq
message in order to avoid the accidental loops
in the routes (in scenarios when the message will be forwarded to the
another RabbitMQ endpoint).
== Using toD
If you need to send messages to a lot of different exchanges, it
makes sense to reuse a endpoint and specify the dynamic destinations
with simple language using xref:eips:toD-eip.adoc[toD].
For example suppose you need to send messages to exchanges with order types,
then using toD could for example be done as follows:
[source,java]
----
from("direct:order")
.toD("spring-rabbit:order-${header.orderType}");
----
== Manual Acknowledgement
If we need to manually acknowledge a message for some use case we can
do it by setting and acknowledgeMode to Manual and using the below snippet
of code to get Channel and deliveryTag to manually acknowledge the message:
[source,java]
----
from("spring-rabbitmq:%s?queues=%s&acknowledgeMode=MANUAL")
.process(exchange -> {
Channel channel = exchange.getProperty(SpringRabbitMQConstants.CHANNEL, Channel.class);
long deliveryTag = exchange.getMessage().getHeader(SpringRabbitMQConstants.DELIVERY_TAG, long.class);
channel.basicAck(deliveryTag, false);
})
----
include::spring-boot:partial$starter.adoc[]