Camelo Apache com Bota de Mola

Camelo Apache com Bota de Mola

1. Visão geral

Na sua essência, o Apache Camel é um mecanismo de integração, que - simplesmente - pode ser usado para facilitar as interações entre uma ampla e variada gama de tecnologias.

Essas pontes entre serviços e tecnologias são chamadas deroutes.. As rotas são implementadas em um mecanismo (oCamelContext) e se comunicam com as chamadas “mensagens de troca”.

2. Dependências do Maven

Para começar, precisaremos incluir dependências para Spring Boot, Camel, API Rest com Swagger e JSON:


    
        org.apache.camel
        camel-servlet-starter
        ${camel.version}
    
    
        org.apache.camel
        camel-jackson-starter
        ${camel.version}
    
    
        org.apache.camel
        camel-swagger-java-starter
        ${camel.version}
    
    
        org.apache.camel
        camel-spring-boot-starter
        ${camel.version}
    
    
        org.springframework.boot
        spring-boot-starter-web
        ${spring-boot-starter.version}
    

As versões mais recentes das dependências do Apache Camel podem ser encontradashere.

3. A classe principal

Vamos primeiro criar um Spring BootApplication:

@SpringBootApplication
@ComponentScan(basePackages="com.example.camel")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4. Configurações de camelo para Spring Boot

Vamos agora configurar nosso aplicativo com Spring, começando com os arquivos de configuração (propriedades).

Por exemplo, vamos configurar um log para nosso aplicativo em um arquivoapplication.properties emsrc/main/resources:

logging.config=classpath:logback.xml
camel.springboot.name=MyCamel
server.address=0.0.0.0
management.address=0.0.0.0
management.port=8081
endpoints.enabled = true
endpoints.health.enabled = true

Este exemplo mostra um arquivoapplication.properties que também define o caminho para uma configuração de Logback. Ao definir o IP como “0.0.0.0”, restringimos totalmente o acesso deadminemanagement no servidor web fornecido pelo Spring Boot. Além disso, habilitamos o acesso de rede necessário aos terminais de nossos aplicativos, bem como aos terminais de verificação de integridade.

Outro arquivo de configuração é oapplication.yml. Nele, vamos adicionar algumas propriedades para nos ajudar a injetar valores em nossas rotas de aplicativo:

server:
  port: 8080
camel:
  springboot:
    name: ServicesRest
management:
  port: 8081
endpoints:
  enabled: false
  health:
    enabled: true
quickstart:
  generateOrderPeriod: 10s
  processOrderPeriod: 30s

5. Setting up the Camel Servlet

Uma maneira de começar a usar o Camel é registrá-lo como um servlet, para que ele possa interceptar as solicitações HTTP e redirecioná-las para o nosso aplicativo.

Como mencionado antes, começando com a versão 2.18 do Camel e abaixo, podemos aproveitar nossoapplication.yml - criando um parâmetro para nosso URL final. Mais tarde, ele será injetado em nosso código Java:

example:
  api:
    path: '/camel'

De volta à nossa classeApplication, precisamos registrar o servlet Camel na raiz de nosso caminho de contexto, que será injetado da referênciaexample.api.path emapplication.yml quando o aplicativo iniciar :

@Value("${example.api.path}")
String contextPath;

@Bean
ServletRegistrationBean servletRegistrationBean() {
    ServletRegistrationBean servlet = new ServletRegistrationBean
      (new CamelHttpTransportServlet(), contextPath+"/*");
    servlet.setName("CamelServlet");
    return servlet;
}

A partir da versão 2.19 do Camel, esta configuração foi descartada, poisCamelServlet é, por padrão, definido como“/camel”.

6. Construindo uma Rota

Vamos começar a fazer uma rota estendendo a classeRouteBuilder do Camel e definindo-a como@Component para que a rotina de verificação do componente possa localizá-la durante a inicialização do servidor web:

@Component
class RestApi extends RouteBuilder {
    @Override
    public void configure() {
        CamelContext context = new DefaultCamelContext();

        restConfiguration()...
        rest("/api/")...
        from("direct:remoteService")...
    }
}

Nesta classe, substituímos o métodoconfigure() da classeRouteBuilder de Camel.

Camel always needs a CamelContext instance - o componente principal onde as mensagens de entrada e saída são mantidas.

Neste exemplo simples,DefaultCamelContext é suficiente, pois apenas vincula mensagens e roteia para ele, como o serviço REST que iremos criar.

6.1. A rotarestConfiguration()

Em seguida, criamos uma declaração REST para os endpoints que planejamos criar no métodorestConfiguration():

restConfiguration()
  .contextPath(contextPath)
  .port(serverPort)
  .enableCORS(true)
  .apiContextPath("/api-doc")
  .apiProperty("api.title", "Test REST API")
  .apiProperty("api.version", "v1")
  .apiContextRouteId("doc-api")
  .component("servlet")
  .bindingMode(RestBindingMode.json)

Aqui, registramos o caminho de contexto com nosso atributo injetado no arquivo YAML. A mesma lógica foi aplicada à porta do nosso aplicativo. O CORS está ativado, permitindo o uso entre sites deste serviço da web. O modo de ligação permite e converte argumentos para nossa API.

Em seguida, adicionamos a documentação do Swagger ao URI, título e versão que definimos anteriormente. À medida que criamos métodos / pontos de extremidade para nosso serviço web REST, a documentação do Swagger será atualizada automaticamente.

Esse contexto do Swagger é, por si só, uma rota Camel, e podemos ver algumas informações técnicas sobre isso no log do servidor durante o processo de inicialização. Nossa documentação de exemplo é fornecida por padrão emhttp://localhost:8080/camel/api-doc.

6.2. A rotarest()

Agora, vamos implementar a chamada de métodorest() a partir do métodoconfigure() listado acima:

rest("/api/")
  .id("api-route")
  .consumes("application/json")
  .post("/bean")
  .bindingMode(RestBindingMode.json_xml)
  .type(MyBean.class)
  .to("direct:remoteService");

Este método é bastante simples para aqueles familiarizados com APIs. Oid é a identificação da rota dentro deCamelContext. A próxima linha define o tipo MIME. O modo de ligação é definido aqui para mostrar que podemos definir um modo norestConfiguration().

O métodopost() adiciona uma operação à API, gerando um endpoint “POST /bean”, enquanto oMyBean (um bean Java regular com umInteger ideString name ) define os parâmetros esperados.

Da mesma forma, ações HTTP como GET, PUT e DELETE também estão disponíveis na forma deget(),put(),delete().

Finalmente, o métodoto() cria uma ponte para outra rota. Aqui, ele diz ao Camel para pesquisar dentro de seu contexto / mecanismo para outra rota que vamos criar - que é nomeada e detectada pelo valor / id “direct: …“, correspondendo à rota definida emfrom()método s.

6.3. A rotafrom() comtransform()

Ao trabalhar com o Camel, uma rota recebe parâmetros e depois converte, transforma e processa esses parâmetros. Depois disso, ele envia esses parâmetros para outra rota que encaminha o resultado para a saída desejada (um arquivo, um banco de dados, um servidor SMTP ou uma resposta da API REST).

Neste artigo, criamos apenas outra rota dentro do métodoconfigure() que estamos substituindo. Será a rota de destino para nossa última rotato():

from("direct:remoteService")
  .routeId("direct-route")
  .tracing()
  .log(">>> ${body.id}")
  .log(">>> ${body.name}")
  .transform().simple("Hello ${in.body.name}")
  .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200));

O métodofrom() segue os mesmos princípios e tem muitos dos mesmos métodos do métodorest(), exceto que consome mensagens de contexto Camel. Este é o motivo do parâmetro “direct-route“, que cria um link para o métodorest().to() acima mencionado.

Many other conversions are available, incluindo extração como primitivos Java (ou objetos) e enviando-o para uma camada de persistência. Observe que as rotas sempre leem das mensagens recebidas, para que as rotas encadeadas ignorem as mensagens enviadas.

Nosso exemplo está pronto e podemos tentar:

  • Execute o comando prompt:mvn spring-boot:run

  • Faça uma solicitação POST parahttp://localhost:8080/camel/api/bean com parâmetros de cabeçalho:Content-Type: application/json e uma carga útil\{“id”: 1,”name”: “World”}

  • Devemos receber um código de retorno 201 e a resposta:Hello, World

6.4. A linguagem de script SIMPLE

O exemplo gera o registro usando o métodotracing(). Observe que usamos os marcadores de posição$\{}; eles fazem parte de uma linguagem de script que pertence a Camel chamada SIMPLE. É aplicado a mensagens trocadas ao longo da rota, como o corpo da mensagem.

Em nosso exemplo, estamos usando SIMPLE para gerar no log os atributos de bean que estão dentro do corpo da mensagem Camel.

Também podemos usá-lo para fazer transformações simples, como foi mostrado com o métodotransform().

6.5. A rotafrom() comprocess()

Vamos fazer algo mais significativo, como chamar uma camada de serviço para retornar os dados processados. SIMPLE não se destina a processamento pesado de dados, então vamos substituir o métodotransform() por um métodoprocess():

from("direct:remoteService")
  .routeId("direct-route")
  .tracing()
  .log(">>> ${body.id}")
  .log(">>> ${body.name}")
  .process(new Processor() {
      @Override
      public void process(Exchange exchange) throws Exception {
          MyBean bodyIn = (MyBean) exchange.getIn().getBody();
          ExampleServices.example(bodyIn);
          exchange.getIn().setBody(bodyIn);
      }
  })
  .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200));

Isso nos permite extrair os dados em um bean, o mesmo previamente definido no métodotype(), e processá-lo em nossa camadaExampleServices.

Como definimosbindingMode() para JSON anteriormente, a resposta já está em um formato JSON adequado, gerado com base em nosso POJO. Isso implica que para uma classeExampleServices:

public class ExampleServices {
    public static void example(MyBean bodyIn) {
        bodyIn.setName( "Hello, " + bodyIn.getName() );
        bodyIn.setId(bodyIn.getId() * 10);
    }
}

A mesma solicitação HTTP agora retorna com um código de resposta 201 e corpo:\{“id”: 10,”name”: “Hello, World”}.

7. Conclusão

Com algumas linhas de código, conseguimos criar um aplicativo relativamente completo. Todas as dependências são criadas, gerenciadas e executadas automaticamente com um único comando. Além disso, podemos criar APIs que unem todos os tipos de tecnologias.

Essa abordagem também é muito fácil de contêiner, resultando em um ambiente de servidor muito enxuto que pode ser facilmente replicado sob demanda. As possibilidades extras de configuração podem ser facilmente incorporadas a um arquivo de configuração de modelo de contêiner.

Este exemplo REST pode ser encontradoover on GitHub.

Finalmente, além das APIsfilter(),process(),transform() emarshall(), muitos outros padrões de integração e manipulações de dados estão disponíveis no Camel: