Introdução e Aplicação do Apache Camel

1.1 Problema a resolver e soluções propostas

1.2 Soluções comuns de EAI

1.3 Como implementar um ESB

1.4 Por que escolher o Camel?

2. Capacidades do Camel

2.1 Visão geral do Apache Camel

2.2 Casos de uso do Camel

2.3 Elementos fundamentais do Camel

2.4 Endpoint

2.5 Exchange

2.6 Processor

2.7 Roteamento (Routing)

2.8 Service

2.9 Contexto CamelContext

3. Exemplos práticos

3.1 Dependências Maven

3.2 Transferir arquivo para um broker de mensagens

3.3 Enviar objeto para middleware de mensagens

3.4 Exemplo produtor/consumidor

3.5 Produtor com dados de consulta SQL

3.6 Consumir mensagem via método de uma classe (primeira forma)

3.7 Consumir mensagem via método de uma classe (segunda forma)

3.8 Consumir mensagem do ActiveMQ

Site oficial: https://camel.apache.org/

Apache Camel é um framework leve para ESB (Enterprise Service Bus). Seus principais conceitos são:

  • Endpoint: componente capaz de receber ou enviar dados, suportando múltiplos protocolos como JMS, HTTP, File, etc.
  • Processor: componente para processar a lógica de negócio.
  • Route: define o fluxo dos dados – de onde vêm, para onde vão e quais procesadores são usados no caminho.

Os processadores trocam dados por meio do objeto Exchange, algo similar ao JMS ou a um "bilhete" passado entre colegas.

Diagrama da arquitetura (conceitual):

Arquitetura Camel

O Camel é um framework de integração empresarial que fornece componentes simples, poderosos e fáceis de usar. O desenvolvedor escolhe diferentes EIP (Enterprise Integration Patterns) conforme a necessidade para atender às mudanças rápidas de negócio. Pode ser visto como uma implementação leve de um barramento de serviços (ESB).

Referência: Artigo original

1.1 Problema a resolver e soluções propostas

Os problemas a serem resolvidos:

  1. Compartilhar e trocar informações entre sistemas heterogêneos internos e externos.
  2. Otimizar a estrutura existente para facilitar a expansão e manutenção.
  3. Garantir que múltiplos sistemas funcionem independentemente, sem interferências.

A essência é a Integração de Aplicações Empresariais (EAI), que estabelece métodos, padrões e tecnologias para troca de informações e colaboração entre sistemas heterogêneos.

1.2 Soluções comuns de EAI

  • SOA (Arquitetura Orientada a Serviços): filosofia de design com múltiplos serviços que cooperam para fornecer funcionalidades completas. Cada serviço é implantado de forma independente e a comunicação ocorre por rede, seguindo contratos e padrões.
  • ESB (Barramento de Serviços Empresariais): funciona como um "tubo" que conecta diferentes nós de serviço. O ESB realiza tradução, interpretação e roteamento de mensagens para permitir a interoperabilidade entre serviços com protocolos distintos.

1.3 Como implementar um ESB

O modelo mais maduro atualmente é o EIP (Enterprise Integration Patterns), que inclui as seguintes especificações:

  • Estilos de Integração (Integration Styles): todos os padrões de integração baseiam-se no modelo de troca de mensagens.
  • Padrões de Canal (Channel Patterns): mensagens trafegam por canais.
  • Padrões de Construção de Mensagens (Message Construction Patterns): descrevem a estrutura das mensagens trocadas.
  • Padrões de Roteamento (Routing Patterns): como distribuir mensagens do remetente ao(s) destinatário(s) correto(s), normalmente sem modificação.
  • Padrões de Transformação (Transformation Patterns): alteram o conteúdo da mensagem para um formato compreensível pelo receptor, incluindo filtragem e mapeamento.
  • Padrões de Ponto Final (Endpoint Patterns): clientes que geram ou recebem mensagens.
  • Padrões de Gerenciamento do Sistema (System Management Patterns): ferramentas para monitoramento do estado do sistema, incluindo tratamento de erros, testes de estresse e monitoramento de mudanças.

1.4 Por que escolher o Camel?

Os frameworks de integração EIP populares são: Spring Integration, Mule ESB e Apache Camel. Segue uma comparação:

  • Spring Integration: oferece suporte básico a File, FTP, JMS, TCP, HTTP, Web Services. Exige grande quantidade de configuração XML (sem DSL real). Resulta em muito trabalho com XML.
  • Mule ESB: é um ESB completo, com funcionalidades extras além da integração. Possui uma DSL melhor que o Spring Integration, mas a lógica de integração tende a ser complexa.
  • Apache Camel: implementa quase todas as tecnologias imagináveis, fornece muitos componentes e permite criar componentes customizados com facilidade. A integração com Spring é madura. O Camel permite dependências sob demanda (só carrega o que for usado).

2. Capacidades do Camel

2.1 Visão geral do Apache Camel

Apache Camel é um framework open source baseado em EIP. Ele implementa modelos de troca de mensagens entre sistemas distintos definidos pelo EIP, como Point-to-Point e Pub/Sub.

Sistema de Mensagens do Camel:

  • Message Endpoint: sistemas heterogêneos que precisam fornecer um endpoint para integração.
  • Message Channel: canal de comunicação entre duas aplicações.
  • Message: unidade padronizada de troca entre endpoints.
  • Message Router: direciona mensagens para diferentes filtros com base em condições, desacoplando etapas individuais de processamento.
  • Message Translator: transforma e mapeia o conteúdo da mensagem durante o transporte, incluindo conversão de formato e mapeamento de dados.
  • Pipes and Filters: processa mensagens complexas mantendo independência e flexibilidade.

2.2 Casos de uso do Camel

  • Agregação de mensagens: combinar dados de diferentes fontes (ActiveMQ, RabbitMQ, WebService) em relatórios.
  • Distribuição de mensagens: encaminhar a mensagem do produtor para consumidores, de forma sequencial ou paralela.
from("amqp:queue:order")
.to("uri:validateBean", "uri:handleBean", "uri:emailBean");

from("amqp:queue:order")
.multicast()
.to("uri:validateBean", "uri:handleBean", "uri:emailBean");
  • Transformação de mensagens: alterar o conteúdo, por exemplo, converter XML para JSON.
from("amqp:queue:order")
.process(new XmlToJsonProcessor())
.to("bean:orderHandler");
  • Motor de regras: usar configuração Spring XML ou DSL para definir rotas. Camel oferece muitos Processors internos para lógica, filtros, etc., facilitando o gerenciamento flexível das rotas.
<route>
    <from uri="amqp:queue:order"/>
    <multicast>
        <to uri="uri:validateBean"/>
        <to uri="uri:handleBean"/>
        <to uri="uri:emailBean"/>
    </multicast>
</route>
from("amqp:queue:order")
.filter(header("foo").isEqualTo("bar"))
.choice()
    .when(xpath("/person/city = 'London'"))
        .to("file:target/messages/uk")
    .otherwise()
        .to("file:target/messages/others");

2.3 Elementos fundamentais do Camel

Os cinco elementos essenciais:

  • Endpoint: para enviar/receber mensagens.
  • Exchange: a mensagem em si.
  • Processor: processador de mensagens.
  • Routing: regras de roteamento.
  • Service: conceito base do Camel.

2.4 Endpoint

Um Endpoint é o ponto de contato entre o Camel e outro sistema. O Camel oferece amplo suporte a protocolos: RPC, HTTP, FTP, etc. Os endpoints são descritos por URIs. A criação de instâncias de Endpoint é feita por implementações da interface org.apache.camel.Component. Para usar um endpoint específico, deve-se adicionar o plugin correspondente (ex: camel-netty4 para Netty4).

2.5 Exchange

O objeto Exchange possui:

  • Properties: armazenamento chave-valor para parâmetros customizados compartilhados ao longo da rota.
  • Patterns: o atributo ExchangePattern (enum org.apache.camel.ExchangePattern) descreve como as mensagens são propagadas (InOnly, InOut, etc.).
  • Message IN/OUT: quando mensagens passam entre Endpoint e Processor ou entre Processors, o Exchange automaticamente usa a saída do elemento anterior como entrada do próximo.

2.6 Processor

Um Processor recebe mensagens de um Endpoint, Rota ou outro Processor e as processa. O Camel fornece muitas implementações prontas, e o desenvolvedor pode criar as suas próprias implementando org.apache.camel.Processor.

public class MeuProcessor implements Processor {
    @Override
    public void process(Exchange exchange) throws Exception {
        Message msg = exchange.getIn();
        String corpo = msg.getBody().toString();
        // ===============
        // Transformação de dados
        // Armazena resultado no out
        // ===============
        if (exchange.getPattern() == ExchangePattern.InOut) {
            Message out = exchange.getOut();
            out.setBody(corpo + " || processado");
        }
    }
}

2.7 Roteamento (Routing)

Define o fluxo entre Endpoints e Processors. Camel suporta roteamento baseado em conteúdo, lista de receptores, roteamento dinâmico, etc.

2.8 Service

No Apache Camel, Service é um conceito mais fundamental que Endpoint, Component ou CamelContext. A maioria dos elementos ativos (Endpoint, Component, CamelContext) são Services. Cada Service tem seu próprio ciclo de vida: inicia com start() e para com stop(). O contexto CamelContext gerencia a ligação entre eles.

2.9 Contexto CamelContext

O CamelContext abrange todo o ciclo de vida do serviço Camel e fornece o ambiente de trabalho para os demais componentes.

3. Exemplos práticos

3.1 Dependências Maven

<!-- Apache Camel core -->
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-core</artifactId>
    <version>2.24.2</version>
</dependency>
<!-- Integração Camel com ActiveMQ -->
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-camel</artifactId>
    <version>5.15.4</version>
</dependency>

3.2 Transferir arquivo para um broker de mensagens

public static void main(String[] args) throws Exception {
    DefaultCamelContext ctx = new DefaultCamelContext();
    ActiveMQConnectionFactory factory =
        new ActiveMQConnectionFactory("admin","admin","http://172.16.2.221:8161");
    ctx.addComponent("activemq", JmsComponent.jmsComponentAutoAcknowledge(factory));
    ctx.addRoutes(new RouteBuilder() {
        @Override
        public void configure() {
            from("file:pasta_entrada?noop=true")
                .to("activemq:queue:minha_fila");
        }
    });
    ctx.start();
}

3.3 Enviar objeto para middleware de mensagens

public static void main(String[] args) throws Exception {
    DefaultCamelContext ctx = new DefaultCamelContext();
    ActiveMQConnectionFactory factory =
        new ActiveMQConnectionFactory("admin","admin","tcp://172.16.2.221:61616");
    ctx.addComponent("activemq", JmsComponent.jmsComponentAutoAcknowledge(factory));
    ctx.addRoutes(new RouteBuilder() {
        @Override
        public void configure() {
            from("direct:inicio")
                .to("activemq:queue:minha_fila");
        }
    });
    ctx.start();
    ProducerTemplate prod = ctx.createProducerTemplate();
    prod.sendBody("direct:inicio", "Mensagem de teste");
}

3.4 Exemplo produtor/consumidor

public static void main(String[] args) throws Exception {
    DefaultCamelContext ctx = new DefaultCamelContext();
    ctx.addRoutes(new RouteBuilder() {
        @Override
        public void configure() {
            from("direct:inicio")
                .process(new Processor() {
                    @Override
                    public void process(Exchange exchange) {
                        System.out.println("Iniciando processamento...");
                        String msg = exchange.getIn().getBody(String.class);
                        msg = msg + " - Modificado";
                        System.out.println("Mensagem modificada: " + msg);
                        exchange.getOut().setBody(msg);
                    }
                })
                .to("seda:fim");
        }
    });
    ctx.start();
    ProducerTemplate prod = ctx.createProducerTemplate();
    prod.sendBody("direct:inicio", "Olá a todos");
    ConsumerTemplate cons = ctx.createConsumerTemplate();
    String resultado = cons.receiveBody("seda:fim", String.class);
    System.out.println("Consumidor recebeu: " + resultado);
}

3.5 Produtor com dados de consulta SQL

Dependências adicionais:

<!-- Camel JDBC -->
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-jdbc</artifactId>
    <version>2.22.1</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
public static void main(String[] args) throws Exception {
    MysqlDataSource ds = new MysqlDataSource();
    ds.setURL("jdbc:mysql://localhost:3306/test");
    ds.setUser("root");
    ds.setPassword("1234");

    SimpleRegistry reg = new SimpleRegistry();
    reg.put("meuDataSource", ds);

    DefaultCamelContext ctx = new DefaultCamelContext(reg);
    ctx.addRoutes(new RouteBuilder() {
        @Override
        public void configure() {
            from("direct:inicio")
                .to("jdbc:meuDataSource")
                .bean(new TratadorResultados(), "exibir");
        }
    });
    ctx.start();
    ProducerTemplate prod = ctx.createProducerTemplate();
    prod.sendBody("direct:inicio", "select * from usuario");
}

public static class TratadorResultados {
    public void exibir(List<?> lista) {
        for (Object item : lista) {
            System.out.println(item);
        }
    }
}

3.6 Consumir mensagem via método de uma classe (primeira forma)

public class ConsumidorMetodo1 {
    public void metodoConsumidor(String mensagem) {
        System.out.println("Consumidor recebeu: " + mensagem);
    }

    public static void main(String[] args) throws Exception {
        DefaultCamelContext ctx = new DefaultCamelContext();
        ctx.addRoutes(new RouteBuilder() {
            @Override
            public void configure() {
                from("direct:inicio")
                    .to("class:br.com.exemplo.ConsumidorMetodo1?method=metodoConsumidor");
            }
        });
        ctx.start();
        ProducerTemplate prod = ctx.createProducerTemplate();
        prod.sendBody("direct:inicio", "Mensagem de teste");
    }
}

3.7 Consumir mensagem via método de uma classe (segunda forma)

public class ConsumidorMetodo2 {
    public void metodoConsumidor(String mensagem) {
        System.out.println("Consumidor recebeu: " + mensagem);
    }

    public static void main(String[] args) throws Exception {
        ConsumidorMetodo2 instancia = new ConsumidorMetodo2();
        SimpleRegistry reg = new SimpleRegistry();
        reg.put("meuServico", instancia);

        DefaultCamelContext ctx = new DefaultCamelContext(reg);
        ctx.addRoutes(new RouteBuilder() {
            @Override
            public void configure() {
                from("direct:inicio")
                    .to("bean:meuServico?method=metodoConsumidor");
            }
        });
        ctx.start();
        ProducerTemplate prod = ctx.createProducerTemplate();
        prod.sendBody("direct:inicio", "Mensagem de teste");
    }
}

3.8 Consumir mensagem do ActiveMQ

public class ConsumidorActiveMQ {
    public static void main(String[] args) throws Exception {
        DefaultCamelContext ctx = new DefaultCamelContext();
        ActiveMQConnectionFactory factory =
            new ActiveMQConnectionFactory("admin","admin","tcp://172.16.2.221:61616");
        ctx.addComponent("activemq", JmsComponent.jmsComponentAutoAcknowledge(factory));
        ctx.addRoutes(new RouteBuilder() {
            @Override
            public void configure() {
                from("activemq:queue:minha_fila").to("seda:fim");
            }
        });
        ctx.start();
        ConsumerTemplate cons = ctx.createConsumerTemplate();
        String msg = cons.receiveBody("seda:fim", String.class);
        System.out.println(msg);
    }
}

O conteúdo será atualizado conforme necessário.

Tags: Apache Camel EIP ESB ActiveMQ JMS

Publicado em 7-9 17:21