发布于:2021-01-16 14:11:16
0
1688
0
自2007年由Apache社区创建以来,开源集成框架apachecamel已经成为开发人员的最爱。它被认为是设计SOA/集成项目和处理复杂的企业集成用例的关键技术。本文是本系列文章的第一部分,它将揭示框架如何从特定领域的语言生成交换发生的路径,如何根据所选的模式进行处理,以及最终如何进行集成。
简介
从一般的观点来看,设计集成体系结构并不是一项显而易见的任务,即使您想要使用的技术和框架相对容易理解和实现。困难在于消息的数量、要应用的转换、交换的同步性或异步性、顺序或并行运行的进程,当然还有对在多个jvm中运行的此类项目的监视。
在传统的Java应用程序中,我们从类调用方法,同时传递和/或返回对象。被调用的方法是链式的,对象传输信息,有时在事务中登记,但总是部署在同一个Java容器中(Web、JEE、Standalone)。除非我们必须调用外部系统或集成遗留应用程序、RDBMS等,否则大多数调用都是本地同步完成的。
如果一个服务想要可重用,它需要被打包,在库中进行版本控制,并与将使用它的项目通信。这种方法适用于由内部开发团队维护的项目,在这些项目中,成本可以由IT部门支持,但它会遇到不同的问题,并且大多数情况下要求我们使用相同的编程语言或特定技术来互连流程(RPC、IIOP等),即部署代码的容器。
图1:SOA
为了允许应用程序在没有此类约束的情况下独立开发,必须在负责使用它的服务的请求/消息的发布者之间促进解耦。这种新的体系结构范例称为面向服务的体系结构,它使用传输层在系统之间交换信息。SOA的一个直接好处是促进基于契约的方法来定义应用程序之间公开的服务,并根据“治理规则”来管理它们。
SOA方法已经能够联合不同的团队,解决围绕更复杂项目开发的问题。这种IT转型是必需的,因为公司需要更灵活地适应市场需求,信息必须实时提供,业务适应需要现有的遗留系统和后台系统的支持。
虽然SOA理念已被广泛采用,但掌握XML、XDS模式、Web服务和业务流程引擎的学习曲线、横向团队的创建和管理,管理服务所需的治理和所需的技能无疑是解释SOA为何仍难以被公司采用的因素。此外,资讯科技部门不仅关心推广和管理网页服务和注册处,而且也关心不同系统之间的互联、交换、转换和验证资讯。在阐述SOA原则时,IT工作的这个集成方面被完全“低估”了。
企业集成模式
2005年,Gregory Hope和Bobby Wolf出版了一本名为《企业集成模式》的书,他们不仅花时间描述复杂的用例,还定义了词汇表、语法和设计图标来表达IT部门必须解决的复杂集成模式。这本书改变了开发团队(业务/功能分析人员、数据建模人员和开发人员)协作设计集成/SOA项目的方式。讨论的重点不仅仅是服务、XML的结构和业务流程的设想,还包括如何使用模式来解决集成用例(聚合、拆分、过滤、基于内容的路由、动态路由)。这本书利用参与者来实现更灵活的编程方法。为了支持本书中描述的EIP并帮助开发人员解决集成用例,apachecamel集成Java框架创建于5年前。
EIP设计图标
发现Apache
表示聚合或路由的EIP模式,这要求我们使用语言“表示”它们。这种语言不是一种新的编程语言,而且是一种特定于某个领域的语言,它充分地描述了所选领域(集成)的问题。apachecamel是一个Java集成框架,它支持omainSspecificLanguage(aka)。DSL;有关更多信息,请参阅Camel文档)使用面向对象的语言,如Java、Scala、Groovy等。不需要解析器、编译器或解释器,而是命令列表、按顺序排列的指令:
instruction1().instruction2()....instructionN();
apachecamel也被定义为“中介和路由”引擎。让我们想想全球道路网:我们可以在城市和首都之间运输不同类型和大小的车辆,运送不同出身、肤色、年龄、性别的乘客。根据交通状况,可以调整行程,使用替代道路。同样,Apache Camel沿着路径传输消息。
from("Brussels") .to("Paris"); // Transport passengers from Brussels Capital to Paris
每个Camel路由都以from指令开始,这一指令特别重要,因为它充当使用者,并根据它是被触发(“事件驱动体系结构”)还是能够定期读取数据(“轮询体系结构”)发挥特定的作用。使用者是一个工厂,每当接收到数据时,就会通过Apache Camel路由创建和传输“消息”。
当然,apachecamel根本不在路线上运输“乘客”,而是运输“信息”。这些消息将通过一系列步骤,即处理器来转换、验证、格式化、丰富所接收信息的内容。该框架提供了不同的处理器,这些处理器经过专门化(Bean、Log),以简化我们希望应用的操作,如下面的代码:
from("Brussels") .bean("Border","validPassport") .log("Passport has been controlled") .bean("Border","controlTicket") .to("log:travel://LogLevel=INFO" + "Ticket has been controlled") .to("Paris");
放置在“from”后面的每个处理器传递信息,并像火车车厢一样“形成”一条链,如下图所示:
from("") ... .to("log:travel://LogLevel=INFO" + "Ticket has been controlled") // .to("file:///outputDirectoryWhereFileWillbeCreated") // .to("http://www.google.be?doASearch") // Call External HTTP Server .to("jms://queue:outputQueue; // Response received is published in a queue
然而,某些处理器会产生一条消息,Camel会将该消息发送到服务器(SMTP、FTP)、应用程序(RDBMS)、代理(JMS)和另一个Camel路由(DIRECT、SEDA、VM),并且在某些情况下会等到收到响应(HTTP、TCP/IP、WS、REST、WebSocket)。
Camel的一个关键好处是,它提供了根据它所携带的信息(使用消息结构)做出决策的可能性。这样一个与对象交换相对应的消息包含了主体中携带的信息或对象,但也包含了头的元数据部分。
元数据允许您记录传输的对象,但也可以知道它们来自何处、它们的来源(文件、Ftp、WebService、SMTP、JDBC、JPA、JMS等)以及它们应该去哪里。为了支持决策,Camel使用一种EIP模式,即基于内容的路由器、过滤器、聚合器、拆分器……以及一种称为表达式语言(Simple、Constant、Xpath、Xquery、SQL、Bean、Header、Body、OGNL、Mvel、EL……)的特定语言。
这些决定是由谓词做出的,我们可以将这些谓词与If/Then/Else、While/For语句进行比较。路由引擎将决定如何处理“消息”以及它们应该去哪里。
如果满足条件,基于内容的路由器使用的选项/时间将计算(使用谓词和表达式语言)。如果是这种情况,则将交换移动到分支路径中定义的处理器,否则它们将移动到另一个管道中。所有这些都体现在以下方面:
// from("Brussels") .bean("Border","validPassport") .choice() .when() .simple(${header.isValid}==true) // Simple language checks if the status is equal to true .log("Passenger has been controlled") .log("We can now control their ticket") .bean("Border","controlTicket") .to("Paris") .otherwise() .log("Your are not authorized to continue your trip");
对于所使用的某些组件,预期接收方(HTTP、WebService、REST、JMS–Request/Reply、TCP/IP等)或发出消息的发送方会发出响应。在这种情况下,Camel将调整用于内部传输消息的模式。此模式通常为InOnly类型,但当需要响应时,将使用InOut模式。为了传输信息并避免将传入消息与传出消息混合,Apache Camel将为此目的使用两个不同的对象,即in或out。当不需要响应时,即我们举例来说,如果使用一个文件组件,那么out对象总是空的。
更进一步
由于流量由运营商控制,apachecamel提供了一个管理路由的环境(启动/停止/暂停/恢复路由中的流量)。这种环境被称为容器,或者更准确地说是上下文。
容器不仅是部署路由的运行时,而且充当复杂的生态系统。它可以跟踪交换,如何使用框架公开的JMX信息进行管理,如何处理线程池,如何发现路由,如何关闭路由并生成创建交换时使用的唯一标识符。
CamelContext还将注册使用或生成该信息所需的组件。根据URI中包含的方案名称,Apache Camel将扫描classloader加载的类,以找到它想要使用的组件:
"scheme://properties?key1=val2&key2=val3 // "file:///home/user/integration? " "timer://myTimer?delay=2s&period=10S"
Component类是一个工厂,它将根据从URI收集的参数创建一个Endpoint对象(?)?键1=值1和键1=值2。此对象包含根据组件扮演的角色创建生产者或使用者所需的方法。
通常,轮询消费者定期扫描文件系统的目录,让JMS的侦听器读取JMS消息,并将创建一个交换,它将传播到下一个处理器,如下所示:
@Override protected int poll() throws Exception { Exchange exchange = endpoint.createExchange(); // create a message body Date now = new Date(); exchange.getIn().setBody("Hello World! The time is " + now); try { // send message to next processor in the route getProcessor().process(exchange); return 1; // number of messages polled } }
在另一端,生产者将等待,直到它从处理器得到一个驼峰交换,然后将操纵“消息”,丰富它并更改“元数据”:
public void process(Exchange exchange) throws Exception { // Add a new property exchange.getIn().setHeader("FrequentFlyer","true); }
Camel项目通常由一个Java主类组成,我们将在其中创建一个DefaultCamelContext,注册Camel路由并启动容器。如以下示例所述,RouteBuilder类是必需的,它的Configure方法调用静态方法(=指令)来设计驼峰路由(=处理器集合)。路由生成器允许创建一到多条驼峰路由:
// public class MainApp { public static void main(String[] args) throws Exception { // CamelContext = container where we will register the routes DefaultCamelContext camelContext = new DefaultCamelContext(); // RouteBuilder = Where we design the Routes using here Java DSL RouteBuilder routeBuilder = new RouteBuilder() { @Override public void configure() throws Exception { from(„file:///travelers“) .bean(“Flight”,”TransportPassenger”) .to(„file:///authorizedTravelers“); } }; // Add the routes to the container camelContext.addRoutes(routeBuilder); // Start the container camelContext.start(); // When work is done we shutdown it camelContext.stop();
与其他集成框架相比,apachecamel是独一无二的,因为它能够处理Java对象,并且能够自动将对象类型转换为处理器或谓词所期望的类型。
在创建CamelContext的过程中,负责进行类型转换的所有类(文件到字符串、读取器、字符串到DOM等等)都将加载到一个内部注册表中,Camel处理器在交换处理过程中会查询到该注册表。这些转换类来自不同的jar,这是java类路径的一部分。虽然apachecamel默认情况下完成了这样一个过程,但是您也可以使用特定的指令来指示应该将哪个特定的转换器应用于接收的对象类型。见下表:
// from("file:///travelers") // The File endpoint polls every 1s second files // available under "travelers" directory .convertBodyTo("String") // We convert Camel Generic File object to a String // which is required by Xpath expression language during Content Based Routing .choice() .when() .xpath("/traveler/@controlled" = 'true') // Check if condition is // matched using as expression left hand side part and condition, right hand side .log("Passenger has been controlled") .to("file:///authorizedTravelers") .otherwise() .log("Your are not authorized to continue your trip");
下一次
在apachecamel文章的第一部分中,我们介绍了这个Java集成框架的一些基本功能,实现了企业集成模式,该模式使用特定于领域的语言来设计在系统/应用程序之间传输消息的路由。
DSL允许我们定义按顺序读取的指令。当Camel组件接收或使用信息时,将创建一个交换,并将其移动到一个处理器集合中,这些处理器对链接到Body对象的消息的内容进行转换。该框架能够使用支持的一种表达式语言(Xpath、Simple、SQL、Header、Body、Constant、EL、JavaScript等)和允许我们定义条件的谓词做出决策(基于内容的路由器、过滤器等)。在交换的传输过程中,Camel将使用包含转换策略的内部注册表自动将对象从和/或转换为特定类型。Camel项目通常使用一个称为CamelContext的容器来注册Camel路由、端点。在本系列的第二部分中,我们将介绍Camel更高级的特性(复杂数据格式的转换、多线程、异步交换等)。
作者介绍