Content-Based Router + Message Filter

TL;DR

O Content-Based Router olha o conteúdo da mensagem (tipo, campo, valor) e a encaminha para um de vários destinos — sem que o produtor saiba quem processa o quê. O Message Filter é o caso degenerado: um router de uma saída que decide passar ou descartar (“essa mensagem me interessa?”). Juntos, são o primeiro filtro-com-decisão do pipeline — a estação que direciona o fluxo. Na lente da família, é o choice().when(...).to(...) do Apache Camel. A armadilha que domina: o router incha de lógica de negócio e vira um God component que centraliza decisões (o ESB-gargalo em miniatura); a saída é manter a regra de roteamento simples e declarativa, e empurrar orquestração complexa para um Routing Slip ou Process Manager.

O problema: o produtor não deveria saber quem processa

Um canal recebe pedidos de tipos variados — nacionais e internacionais, comuns e prioritários. Cada tipo vai para um sistema diferente. Se o produtor decide o destino, ele precisa conhecer todos os sistemas downstream e sua lógica de despacho — acoplamento que a mensageria deveria justamente eliminar. E se cada consumidor lê tudo e ignora o que não é seu, você desperdiça processamento e espalha a regra de “isto é meu” por todo lugar.

O Content-Based Router resolve pondo um filtro-decisor no meio: ele inspeciona a mensagem e a manda para o destino certo. O produtor publica num canal só, ignorante dos destinos; o roteador — e ele — conhece o mapa de “que conteúdo vai para onde”.

A ideia: uma entrada, uma de N saídas


graph LR
    IN["pedido"] --> R{{"Content-Based Router<br/>olha pedido.tipo"}}
    R -->|"internacional"| A["fila alfândega"]
    R -->|"prioritário"| B["fila expressa"]
    R -->|"comum"| C["fila padrão"]

    style R fill:#4A90D9,color:#fff
    style A fill:#F5A623,color:#000
    style B fill:#F5A623,color:#000
    style C fill:#F5A623,color:#000

O router examina o conteúdo e escolhe exatamente um destino. Repare que ele não transforma a mensagem (isso é Translator) nem a duplica para vários (isso é Recipient List) — ele só decide o caminho. Em Camel: from("pedidos").choice().when(header("tipo").isEqualTo("intl")).to("alfandega")....

O Message Filter: um router de uma saída

O Message Filter é o router levado ao mínimo: uma saída, e a decisão é binária — a mensagem passa ou é descartada. É o “essa mensagem me interessa?” Um consumidor que só liga para pedidos acima de R$ 1000 põe um filtro na entrada e ignora o resto sem custo downstream.

A lente cross-ferramenta

FerramentaContent-Based RouterMessage Filter
Apache Camelchoice().when(predicate).to(...)filter(predicate)
Spring Integration@Router / PayloadTypeRouter@Filter / MessageFilter
RabbitMQtopic exchange + routing keys (roteamento por chave, não por payload)binding com routing key
Kafka Streamsbranch() / split()filter()

Nuance importante: o RabbitMQ roteia por routing key (um campo do envelope), não pelo payload — é roteamento baseado em header, não em conteúdo profundo. Content-Based Router “de verdade” (inspecionar o corpo) costuma exigir uma camada de aplicação (Camel/Spring Integration) por cima do broker.

Armadilhas comuns

O God Router com lógica de negócio

O que acontece: o choice() cresce para 40 when(...) com condições que consultam serviços, fazem cálculo e embutem regra de negócio — o roteador vira o cérebro do sistema. Por quê: é o ESB-gargalo em miniatura (smart endpoints, dumb pipes): centralizar decisão de negócio no pipe acopla todos os fluxos a um ponto que todo time precisa mudar e ninguém entende. O router deveria só direcionar, não decidir o negócio. Como evitar: mantenha a condição de roteamento simples e declarativa (um campo, um tipo). Quando a escolha do caminho depende de lógica de negócio real ou de uma sequência de passos, é um Process Manager ou Routing Slip (o roteiro viaja na mensagem), não mais um when no router.

Regras de roteamento espalhadas e duplicadas

O que acontece: a mesma decisão (“internacional → alfândega”) aparece em três routers diferentes; muda a regra, e você conserta em dois lugares e esquece o terceiro. Por quê: roteamento é uma regra que tende a se repetir; copiada, ela diverge silenciosamente e cria comportamento inconsistente entre fluxos. Como evitar: centralize a regra de roteamento num só lugar (um router canônico, ou configuração externa); os demais fluxos referenciam, não recopiam. Roteamento por configuração (tabela) em vez de if hard-coded facilita manter a regra única.

Router acoplado a destinos hard-coded

O que acontece: os destinos ("alfandega", "expressa") estão escritos no código do router; adicionar um tipo novo de pedido exige recompilar e redeployar o roteador. Por quê: hard-codear destinos transforma uma mudança de configuração numa mudança de código, e acopla o router à topologia concreta — frágil quando os destinos mudam com frequência. Como evitar: externalize o mapa conteúdo→destino (configuração, tabela de roteamento). Um Dynamic Router aprende os destinos em runtime; no mínimo, os endereços vêm de config, não de literais no código.

Como explicar em inglês

“A Content-Based Router looks at the message content — a type, a field, a value — and routes it to one of several destinations, so the producer never needs to know who processes what. A Message Filter is the degenerate case: a router with a single output that decides pass or discard — ‘do I care about this message?’ Together they’re the first decision-making filter in the pipeline, the station that steers the flow, and in this family’s lens they’re Camel’s choice().when(...).to(...) and filter(...). The dominant trap is the router bloating with business logic into a God component that centralizes decisions — the ESB bottleneck in miniature — so you keep the routing condition simple and declarative and push complex orchestration to a Routing Slip or Process Manager, where the itinerary travels with the message. And watch the nuance that RabbitMQ routes by routing key, a header field, not by deep payload content — true content-based routing usually needs an application layer like Camel on top.”

PTEN
roteador por conteúdocontent-based router
filtro de mensagemmessage filter
passar ou descartarpass or discard
roteamento por configuraçãoconfiguration-driven routing
roteiro na mensagem (routing slip)routing slip
chave de roteamentorouting key
roteador dinâmicodynamic router

O que vem a seguir

O router escolhe um caminho para a mensagem inteira. Mas e quando a mensagem é composta — um pedido com vários itens que precisam ser processados separadamente e depois recombinados? Aí entra o par mais famoso do EIP: quebrar em partes e juntar de volta.

Veja também

Fontes

  • Gregor Hohpe & Bobby WoolfEnterprise Integration Patterns (2004) — Content-Based Router, Message Filter, Dynamic Router, Routing Slip.
  • Gregor HohpeContent-Based Router e Message Filter — as definições canônicas.
  • Apache CamelContent Based Router EIP — o choice() como roteador por conteúdo.