博客 / 詳情

返回

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

        <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-spring-boot-starter</artifactId>
            <version>3.18.1</version>
        </dependency>

本例是藉由camel-jetty-http 實現的REST web server,因此我們需要引入該依賴:

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-netty-http</artifactId>
            <version>3.18.1</version>
            <!-- use the same version as your Camel core version -->
        </dependency>

本例實現的API有POST請求,傳遞的數據格式為json,需要引入camel-jackson依賴

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-jackson</artifactId>
            <version>3.18.1</version>
            <!-- use the same version as your Camel core version -->
        </dependency>

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以轉換數據

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-http</artifactId>
            <version>3.18.1</version>
            <!-- use the same version as your Camel core version -->
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-jackson</artifactId>
            <version>3.18.1</version>
            <!-- use the same version as your Camel core version -->
        </dependency>

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<PlusResponse> 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方法指明轉換器和輸出格式以處理輸出

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.