Apache Camel's Bean Enterprise Integration Pattern (EIP) lets you invoke POJO methods directly within routes, seamlessly integrating custom business logic without heavy frameworks. This article presents a fully self-contained, runnable Java example using Camel Main, featuring header manipulation and enhanced logging for real-world demonstration. The code requires only camel-core on the classpath.
Key Features Demonstrated
- Timer-triggered message flow every 2 seconds.
- Bean method invocation with body and headers parameter binding.
- Custom header enrichment (processor metadata, timestamps).
- Split routes using
directfor modularity. - Infinite runtime via
Camel Main(Ctrl+C to stop).
The bean processes the message body, uppercases it, adds headers tracking processing details, and returns the transformed body.
Complete Runnable Code
Here's the entire application in a single file—compile and run directly:
import org.apache.camel.Body;
import org.apache.camel.Headers;
import org.apache.camel.builder.RouteBuilder;
import java.util.Map;
/**
* Apache Camel example demonstrating bean method invocation in a route.
* Uses a timer-based route that processes messages through a custom bean.
*/
public class BeanExampleApp {
static void main(String[] args) throws Exception {
// Create a new Camel Main instance (using fully qualified name to avoid conflict)
org.apache.camel.main.Main main = new org.apache.camel.main.Main();
// Add routes with bean processing
main.configure().addRoutesBuilder(new RouteBuilder() {
@Override
public void configure() {
// Route 1: Timer that fires every 2 seconds
from("timer:beanTick?period=2000")
.setBody().constant("hello from timer")
.log("${body}")
.to("direct:process")
.log("${body}");
// Route 2: Process the message using a bean
from("direct:process")
.bean(new MyProcessor(), "process") // Invoke bean method
.log("After bean: ${body}")
.log("Headers - ProcessedBy: ${header.ProcessedBy}, ProcessedAt: ${header.ProcessedAt}, OriginalBody: ${header.OriginalBody}");
}
});
// Run Camel (will run until Ctrl+C is pressed)
main.run(args);
}
/**
* Custom processor bean that processes messages.
* Accepts body as String and headers as Map for manipulation.
*/
public static class MyProcessor {
public String process(@Body String body, @Headers Map<String, Object> headers) {
// Add custom headers
headers.put("ProcessedBy", "MyProcessor");
headers.put("ProcessedAt", System.currentTimeMillis());
headers.put("OriginalBody", body);
// Process and return the modified body
return body.toUpperCase() + " - processed by MyProcessor";
}
}
}
Expected Output
Console logs repeat every 2 seconds:
hello from timer
After bean: HELLO FROM TIMER - processed by MyProcessor
Headers - ProcessedBy: MyProcessor, ProcessedAt: 1769775068470, OriginalBody: hello from timer
HELLO FROM TIMER - processed by MyProcessor
Best Practices Highlighted
-
Parameter Binding: Use annotations like
@Body,@Headers,@Header("name")for type-safe access; raw types work for simple cases. -
Method Selection: Explicitly name
"process"method to avoid ambiguity with overloads. -
Inline Beans: Perfect for simple processors; use registry lookup for complex or shared beans.
-
Route Modularity:
direct:endpoints enable clean separation of concerns.
This pattern excels for transformations, validations, and custom logic in enterprise integration routes.
Leave a Reply