Hi everyone,
recently we had a typo in one of our route definitions that resulted in a
duplicate route ID but no error message and unexpected replacement of an
existing route. This is the bootstrap order found in some Camel examples:
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:foo").routeId("foo").stop();
}
});
context.addRoutes(new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:bar").routeId("foo").stop();
}
});
context.start();
You'll get a duplicate route ID exception.
If instead you start the context before you add the routes, you won't get an
exception and the "direct:bar" route will simply replace the "direct:foo"
route, as they have the same ID. This is consistent with the Javadoc of the API
and probably a useful feature.
However if like in our case you use camel-spring-boot, the RouteCollector will
add routes after the Camel context has started. You won't detect duplicate
route IDs but instead any later discovered RouteBuilder will override existing
routes with the same ID.
I'm no Spring expert but it seems the CamelContext start should be deferred in
the Spring Boot integration code: The CamelBeanPostProcessor factory method
triggers CamelContext creation (due to injection in the factory method) and
starts SpringCamelContext during the BeanPostProcessor initialization phase in
Spring (InitializingBean). Any necessary transitive bean creation will
therefore also happen in that phase. We see a lot of Spring warnings (actually
INFO, but it probably should be WARN) that some BeanPostProcessors had to be
skipped, because we are starting inside a BeanPostProcessor call.
One of those is for example our custom BeanPostProcessor which adds discovered
EventNotifiers to the CamelContext, something the Spring Boot integration
doesn't provide yet. We think this has to be done before the CamelContext is
started, after looking at the ManagementStrategy code. Hence you can't do this
with the CamelConfiguration interface of camel-spring-boot, the context has
already been started at that point.
Our solution was a simple integration class for Spring Boot that starts the
context later, after configuration. Would be great to know if we are missing
something, although we'll probably stay on 2.14 anyway for this project due end
of March.
Cheers,
Christian