blob: a3322672f2bf95c67904846b04606a832254f6e9 [file]
= Contexts and Dependency Injection (CDI) in Camel Quarkus
:page-aliases: cdi.adoc
CDI plays a central role in Quarkus and Camel Quarkus offers a first class support for it too.
You may use `@Inject`, `@ConfigProperty` and similar annotations e.g. to inject beans and configuration values to
your Camel `RouteBuilder`. Here is the `RouteBuilder` from our `timer-log-cdi` xref:user-guide/examples.adoc[example]:
[source,java]
----
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import org.apache.camel.builder.RouteBuilder;
import org.eclipse.microprofile.config.inject.ConfigProperty;
@ApplicationScoped <1>
public class TimerRoute extends RouteBuilder {
@ConfigProperty(name = "timer.period", defaultValue = "1000") <2>
String period;
@Inject
Counter counter;
@Override
public void configure() throws Exception {
fromF("timer:foo?period=%s", period)
.setBody(exchange -> "Incremented the counter: " + counter.increment())
.to("log:cdi-example?showExchangePattern=false&showBodyType=false");
}
}
----
<1> The `@ApplicationScoped` annotation is required for `@Inject` and `@ConfigProperty` to work in a `RouteBuilder`.
Note that the `@ApplicationScoped` beans are managed by the CDI container and their life cycle is thus a bit more
complex than the one of the plain `RouteBuilder`. In other words, using `@ApplicationScoped` in `RouteBuilder` comes
with some boot time penalty and you should therefore only annotate your `RouteBuilder` with `@ApplicationScoped` when
you really need it.
<2> The value for the `timer.period` property is defined in `src/main/resources/application.properties` of the example project.
TIP: Please refer to the https://quarkus.io/blog/quarkus-dependency-injection[Quarkus Dependency Injection guide] for more details.
== Accessing `CamelContext`
To access `CamelContext` just inject it into your bean:
[source,java]
----
import javax.inject.Inject;
import javax.enterprise.context.ApplicationScoped;
import java.util.stream.Collectors;
import java.util.List;
import org.apache.camel.CamelContext;
@ApplicationScoped
public class MyBean {
@Inject
CamelContext context;
public List<String> listRouteIds() {
return context.getRoutes().stream().map(Route::getId).sorted().collect(Collectors.toList());
}
}
----
== `@EndpointInject` and `@Produce`
If you are used to `@org.apache.camel.EndpointInject` and `@org.apache.camel.Produce` from
xref:manual::pojo-producing.adoc[plain Camel] or from Camel on SpringBoot, you can continue using them on Quarkus too.
This is supported since Camel Quarkus 2.0.0.
The following use cases are supported by `org.apache.camel.quarkus:camel-quarkus-core`:
[source,java]
----
import javax.enterprise.context.ApplicationScoped;
import org.apache.camel.EndpointInject;
import org.apache.camel.FluentProducerTemplate;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
@ApplicationScoped
class MyBean {
@EndpointInject("direct:myDirect1")
ProducerTemplate producerTemplate;
@EndpointInject("direct:myDirect2")
FluentProducerTemplate fluentProducerTemplate;
@EndpointInject("direct:myDirect3")
DirectEndpoint directEndpoint;
@Produce("direct:myDirect4")
ProducerTemplate produceProducer;
@Produce("direct:myDirect5")
FluentProducerTemplate produceProducerFluent;
}
----
You can use any other Camel producer endpoint URI instead of `direct:myDirect*`.
[WARNING]
====
`@EndpointInject` and `@Produce` are not supported on setter methods
- see https://github.com/apache/camel-quarkus/issues/2579[#2579]
====
The following use case is supported by `org.apache.camel.quarkus:camel-quarkus-bean`:
[source,java]
----
import javax.enterprise.context.ApplicationScoped;
import org.apache.camel.Produce;
@ApplicationScoped
class MyProduceBean {
public interface ProduceInterface {
String sayHello(String name);
}
@Produce("direct:myDirect6")
ProduceInterface produceInterface;
void doSomething() {
produceInterface.sayHello("Kermit")
}
}
----
== CDI and the Camel Bean component
`org.apache.camel.quarkus:camel-quarkus-bean` artifact brings support for the following features:
=== Refer to a bean by name
To refer to a bean in a route definition by name, just annotate the bean with `@Named("myNamedBean")` and
`@ApplicationScoped` (or some other
https://quarkus.io/guides/cdi-reference#supported_features[supported] scope). The `@RegisterForReflection` annotation
is important for the native mode.
[source,java]
----
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import io.quarkus.runtime.annotations.RegisterForReflection;
@ApplicationScoped
@Named("myNamedBean")
@RegisterForReflection
public class NamedBean {
public String hello(String name) {
return "Hello " + name + " from the NamedBean";
}
}
----
Then you can use the `myNamedBean` name in a route definition:
[source,java]
----
import org.apache.camel.builder.RouteBuilder;
public class CamelRoute extends RouteBuilder {
@Override
public void configure() {
from("direct:named")
.bean("namedBean", "hello");
/* ... which is an equivalent of the following: */
from("direct:named")
.to("bean:namedBean?method=hello");
}
}
----
NOTE: We aim at supporting all use cases listed in xref:manual::bean-binding.adoc[Bean binding] section of Camel documentation.
Do not hesitate to https://github.com/apache/camel-quarkus/issues[file an issue] if some bean binding scenario does not work for you.
=== `@Consume`
Since Camel Quarkus 2.0.0, the `camel-quarkus-bean` artifact brings support for `@org.apache.camel.Consume`
- see the xref:manual::pojo-consuming.adoc[Pojo consuming] section of Camel documentation.
Declaring a class like the following
[source,java]
----
import org.apache.camel.Consume;
public class Foo {
@Consume("activemq:cheese")
public void onCheese(String name) {
...
}
}
----
will automatically create the following Camel route
[source,java]
----
from("activemq:cheese").bean("foo1234", "onCheese")
----
for you.
Note that Camel Quarkus will implicitly add `@javax.inject.Singleton` and `javax.inject.Named("foo1234")` to the bean class, where `1234` is a hash code obtained from the fully qualified class name.
If your bean has some CDI scope (such as `@ApplicationScoped`) or `@Named("someName")` set already,
those will be honored in the auto-created route.