Apache Camel: Introduction & Core Concepts

Apache Camel is an open-source integration framework that implements Enterprise Integration Patterns (EIPs). It provides a routing and mediation engine that lets you define routing rules in Java DSL, XML, or annotations, connecting hundreds of components like files, HTTP, databases, message queues, and cloud services.

Contents

Core Concepts

Camel builds integration logic from a small set of composable abstractions. Understanding these six building blocks is the foundation for everything else.

ConceptWhat it is
CamelContextThe runtime container: holds routes, components, configurations, and the type converter registry. There is typically one per application.
RouteA processing pipeline defined as a sequence of steps from a source endpoint through processors to one or more destination endpoints.
EndpointA channel to a system or resource, described by a URI such as file:data/inbox or kafka:orders?brokers=localhost:9092.
ComponentA factory for endpoints. Over 300 components are available: file, HTTP, Kafka, JPA, AWS S3, and more.
ExchangeThe message container that travels through a route. Holds an in-message, an optional out-message, headers, and properties.
ProcessorA single processing step that receives an Exchange, transforms or inspects it, and passes it on.

Your First Route

Add the Camel BOM and a starter dependency, then define a route using RouteBuilder. This example fires a timer every second and logs a message.

XML
<!-- Camel BOM — manages all camel-* versions -->
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-bom</artifactId>
      <version>4.6.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<!-- Core Camel (standalone, no Spring) -->
<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-core</artifactId>
</dependency>
Java
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;

public class HelloCamel {

    public static void main(String[] args) throws Exception {
        DefaultCamelContext context = new DefaultCamelContext();

        context.addRoutes(new RouteBuilder() {
            @Override
            public void configure() {
                from("timer:tick?period=1000")  // fire every 1 second
                    .log("Hello Camel!");        // log to console
            }
        });

        context.start();
        Thread.sleep(5000); // let it run for 5 seconds
        context.stop();
    }
}
The URI timer:tick?period=1000 uses the timer component (name tick) with a query parameter period=1000 ms. This pattern, component:name?options, is universal across all Camel components.

Enterprise Integration Patterns

Camel ships implementations of the classic EIP patterns from the Hohpe & Woolf book. Here are four of the most commonly used:

PatternDSL keywordWhat it does
Content-Based Router.choice().when().otherwise()Routes a message to one of several destinations based on message content or headers.
Message Filter.filter()Passes the message on only if a predicate evaluates to true; drops it silently otherwise.
Splitter.split()Splits a single message (e.g. a JSON array) into multiple individual messages for processing.
Aggregator.aggregate()Collects multiple related messages and combines them into a single message using a strategy.
Java
// Content-Based Router example
from("direct:orders")
    .choice()
        .when(header("type").isEqualTo("VIP"))
            .to("direct:vipOrders")
        .when(header("type").isEqualTo("STANDARD"))
            .to("direct:standardOrders")
        .otherwise()
            .to("direct:unknownOrders")
    .end();

// Splitter example — splits a comma-separated body into individual messages
from("direct:batch")
    .split(body().tokenize(","))
        .log("Processing item: ${body}")
    .end();

DSL Styles

Camel supports three equivalent ways to define routes. All three examples below define the same route: poll a file every 5 seconds and log its name.

Java DSL (RouteBuilder)

Java
import org.apache.camel.builder.RouteBuilder;

public class MyRoute extends RouteBuilder {
    @Override
    public void configure() {
        from("file:data/inbox?delay=5000")
            .log("Processing file: ${header.CamelFileName}");
    }
}

YAML DSL (camel-yaml-dsl: routes.yaml)

YAML
- route:
    from:
      uri: "file:data/inbox"
      parameters:
        delay: 5000
    steps:
      - log:
          message: "Processing file: ${header.CamelFileName}"

XML DSL (camelContext in Spring XML or standalone)

XML
<camelContext xmlns="http://camel.apache.org/schema/spring">
  <route>
    <from uri="file:data/inbox?delay=5000"/>
    <log message="Processing file: ${header.CamelFileName}"/>
  </route>
</camelContext>
Java DSL gives the best IDE support (auto-complete, refactoring). YAML DSL is preferred for configuration-driven deployments (Kubernetes, Camel K). XML DSL is legacy but still fully supported.

Key Components Overview

Camel has over 300 components. These are the ones you will encounter most often:

ComponentProtocol / TechnologyExample URI
fileLocal filesystem polling & writingfile:data/inbox?delete=true
http / httpsHTTP client callshttps://api.example.com/orders
timerPeriodic trigger (no external system)timer:tick?period=5000
kafkaApache Kafka produce & consumekafka:orders?brokers=localhost:9092
directIn-memory synchronous call between routesdirect:processOrder
sedaIn-memory async queue between routesseda:asyncWork?concurrentConsumers=5
jpaJPA entity polling & persistencejpa:com.example.Order?delay=5000
restREST DSL: expose REST endpointsrest("/api").get("/hello")

The Exchange

The Exchange is the envelope that carries a message through a route. It holds the in-message body, headers, properties, and an optional out-message for request-reply scenarios. You access it in a Processor or via the exchange Simple language variable.

Java
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;

public class ExchangeRoute extends RouteBuilder {

    @Override
    public void configure() {
        from("timer:tick?period=2000")
            .setBody(constant("Hello from Camel"))
            .setHeader("myHeader", constant("customValue"))
            .process(new Processor() {
                @Override
                public void process(Exchange exchange) throws Exception {
                    // Read body
                    String body = exchange.getMessage().getBody(String.class);

                    // Read a header
                    String header = exchange.getMessage().getHeader("myHeader", String.class);

                    // Read an exchange property (set earlier in the route)
                    Object prop = exchange.getProperty("someProperty");

                    System.out.println("body=" + body + " header=" + header);

                    // Modify the body
                    exchange.getMessage().setBody(body.toUpperCase());
                }
            })
            .log("Result: ${body}");
    }
}
Use exchange.getMessage() (Camel 3+) rather than the deprecated exchange.getIn(). Properties (set via setProperty) survive the whole route; headers are per-message and may be cleared by some components.