Apache Camel构建与集成REST Web Service

1. 什么是Apache Camel

1.1 什么是Apache Camel?

Apache Camel 是一款基于Enterprise Integration Patterns的开源集成框架。

Enterprise Integration Patterns 企业集成模式,是一本关于使用消息传递进行企业服务集成的书籍。这本书提供了65种模式用于处理异步消息传递。Camel支持了其中的绝大部分的模式。

1.2 Apache Camel核心概念

  • CamelContext

    CamelContext是一个对象,表示Camel runtime system。一般一个应用中只会有一个CamelContext对象。CamelContext可以管理Route,可以维护一个Name to Component的Map。

  • EndPoint

    在Camel的语境下,Endpoint可以是任何能够提供或者消费消息的事物,如一个JMS队列,一个web service,一个文件,一个FTP服务器,一个POJO。

  • Component

    Component是Endpoint的工厂,Component和Endpoint同样也是Camel中的接口,各自有诸多的实现如JmsComponent,JmsEndpoint以实现不同的功能。

  • CamelTemplate

    CamelTemplate 类是对CamelContext的一个简单包装,可以用来给Endpoint发送Message或者Exchange。

  • Message 和 Exchange

    Message和Exchange都是Camel提供的接口,Camel同样也提供了诸多的实现如JmsMessage,JmsExchange等。

  • Processor

    Processor接口用以处理Message或者Exchange,Camel同样也提供了一些实现,开发者也可以自行实现这个接口以完成不同的逻辑。

  • Routes 和 RouteBuilder

    Route是一个Message入队到出队的所有流程。

    开发者可以自行继承RouteBuilder类以自定义Route。

2. 使用Apache Camel构建REST Web Service

使用Apache Camel构建REST Web服务并不是Camel本身提供的能力,这也不是常见的工程实践。

2.1 如何实现

Apache Camel是通过一些Camel REST component建立对应的endpoint并定义Camel Route来实现Web服务的。能够提供Rest DSL的component有:

  • camel-rest (需要提供基本的rest component),
  • camel-natty-http,
  • camel-jetty,
  • camel-platform-http,
  • camel-servlet,
  • camel-undertow

等等。

2.2 初始化项目

该项目是一个使用maven构建的Spring 项目,实现了加法的功能

2.3 引入依赖

首先需要引入camel

        
            org.apache.camel.springboot
            camel-spring-boot-starter
            3.18.1
        

本例是借由camel-jetty-http 实现的REST web server,因此我们需要引入该依赖:

        
            org.apache.camel
            camel-netty-http
            3.18.1
            
        

本例实现的API有POST请求,传递的数据格式为json,需要引入camel-jackson依赖

        
            org.apache.camel
            camel-jackson
            3.18.1
            
        

2.4 创建Route

本例实现了两个API如下:

Http Method Path Request Body Response Body
1 POST /add {"first": 5, "second": 6} {"result": 11}
2 GET /foo Bye World.
import adder.dto.AdderRequest;
import adder.dto.AdderResponse;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.rest.RestBindingMode;
import org.springframework.stereotype.Component;

@Component
public class AdderRouteBuilder extends RouteBuilder {
    @Override
    public void configure() {

        restConfiguration()
                .component("netty-http")
                .host("localhost")
                .port(8086)    // 注1
                .bindingMode(RestBindingMode.json)
                .dataFormatProperty("json.in.disableFeatures", "FAIL_ON_UNKNOWN_PROPERTIES,ADJUST_DATES_TO_CONTEXT_TIME_ZONE")
                .dataFormatProperty("json.in.enableFeatures", "FAIL_ON_NUMBERS_FOR_ENUMS,USE_BIG_DECIMAL_FOR_FLOATS");

        rest()
                .post("/add")
                .type(AdderRequest.class)    // 注2
                .outType(AdderResponse.class)    // 注3
                .produces("application/json")    // 注4
                .consumes("application/json")
                .to("bean:adder?method=add");    // 注5

        from("netty-http:http://localhost:8088/foo")
                .transform().constant("Bye World.");    // 注6

    }
}

注1:由于该应用是借由camel-netty-http component实现的服务,因此需要额外声明指定端口。如果使用和本身Spring应用一样的端口(如果没有指定,那么默认为8080端口),那么请求该端口只会获得Spring本身定义的服务,而不是camel-netty-http提供的服务。

注2:定义输入的类型,即Request Body的类型,需要自行实现AdderRequest类

注3:定义输出的类型,即Response Body的类型,需要自行实现AdderResponse类

注4:定义输出的格式

注5:定义需要调用的Camel endpoint,bean指的是Spring应用的Bean,Spring应用的Bean也可以理解为camel的component。(注意:自定义bean时使用的注解@Component是来源于SpringBoot,而不是Camel)使用Bean component时,其URI格式为 bean:beanName[?options] 具体实现可参考2.5 定义处理方法

注6:同一个endpoint也可以同时监听其他的端口

2.5 定义处理方法

import adder.dto.AdderRequest;
import adder.dto.AdderResponse;
import org.springframework.stereotype.Component;

@Component
public class Adder {
    public AdderResponse add(AdderRequest adderRequest) {
        return new AdderResponse(adderRequest.getFirst() + adderRequest.getSecond());
    }
}

3. 使用Apache Camel 集成 REST Web Service

3.1 初始化项目

本项目是一个maven构建的Spring项目,消费了上一部分提供的加法功能

3.2 引入依赖

首先需要引入Camel

其次需要引入camel-http以消费http服务,引入camel-jackson以转换数据

        
            org.apache.camel
            camel-http
            3.18.1
            
        
        
            org.apache.camel
            camel-jackson
            3.18.1
            
        

3.3 实现controller

Http Method Path Request Body Response Body
1 POST /plus {"first-in": 5, "second-in": 6} {"result-out": 11}
import calculator.dto.PlusRequest;
import calculator.dto.PlusResponse;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.ExchangeBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CalculatorController {

    @Autowired
    private ProducerTemplate producerTemplate;

    @Autowired
    private CamelContext camelContext;

    @PostMapping("/plus")
    public ResponseEntity number(@RequestBody PlusRequest request) {
        final Exchange requestExchange = ExchangeBuilder.anExchange(camelContext).withBody(request).build();
        return ResponseEntity.ok(producerTemplate.send("direct:addRoute", requestExchange).getIn().getBody(PlusResponse.class));
    }
}

"direct:addRoute" 为自定义的一个URI,可以在RouteBuilder中指明

3.4 定义Route

import calculator.dto.PlusResponse;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.dataformat.JsonLibrary;
import org.springframework.stereotype.Component;

@Component
public class CalculatorRouteBuilder extends RouteBuilder {
    @Override
    public void configure() {

        from("direct:addRoute")    // 注1
                .setHeader(Exchange.HTTP_METHOD, simple("POST"))
                .setHeader("Content-Type", constant("application/json"))
                .setHeader("Accept", constant("application/json"))
                .marshal()    // 注2
                .json(JsonLibrary.Jackson)
                .toD("http://localhost:8086/add")
                .unmarshal()    // 注3
                .json(JsonLibrary.Jackson, PlusResponse.class)
                .process();
    }
}

注1:from方法为创建一个从指定URI开始的route,相当于在此处声明了自定义的URI

注2:使用marshal方法和json方法指明转换器以处理输入

注3:使用unmarshal方法和json方法指明转换器和输出格式以处理输出

你可能感兴趣的:(camelrest)