apache camel

这是本教程的第二部分,我们将使用Apache Camel创建发票处理应用程序。 如果您错过了它,一定要看一下第一部分 。 以前,我们已经定义了系统的功能要求,创建了网关,分离器,过滤器和基于内容的路由器组件。 让我们继续创建一个转换器。

5.将发票转换为付款

现在,我们已经成功地从系统中过滤掉了“过于昂贵”的发票(它们可能需要人工检查等)。 重要的是,我们现在可以收取发票并从中产生付款。 首先,让我们将Payment类添加到banking包中:

package com.vrtoonjava.banking;import com.google.common.base.Objects;import java.math.BigDecimal;public class Payment {private final String senderAccount;private final String receiverAccount;private final BigDecimal dollars;public Payment(String senderAccount, String receiverAccount, BigDecimal dollars) {this.senderAccount = senderAccount;this.receiverAccount = receiverAccount;this.dollars = dollars;}public String getSenderAccount() {return senderAccount;}public String getReceiverAccount() {return receiverAccount;}public BigDecimal getDollars() {return dollars;}@Overridepublic String toString() {return Objects.toStringHelper(this).add("senderAccount", senderAccount).add("receiverAccount", receiverAccount).add("dollars", dollars).toString();}}

因为我们将有两种方法(从本地和国外发票)创建付款,所以我们定义一个用于创建付款的通用合同(界面)。 将界面PaymentCreator放入banking包:

package com.vrtoonjava.banking;import com.vrtoonjava.invoices.Invoice;/*** Creates payment for bank from the invoice.* Real world implementation might do some I/O expensive stuff.*/
public interface PaymentCreator {Payment createPayment(Invoice invoice) throws PaymentException;}

从技术上讲,这是一个简单的参数化工厂。 请注意,它将引发PaymentException 。 稍后我们将进行异常处理,但这是简单的PaymentException的代码:

package com.vrtoonjava.banking;public class PaymentException extends Exception {public PaymentException(String message) {super(message);}}

现在,我们可以将两个实现添加到invoices包中了。 首先,让我们创建LocalPaymentCreator类:

package com.vrtoonjava.invoices;import com.vrtoonjava.banking.Payment;
import com.vrtoonjava.banking.PaymentCreator;
import com.vrtoonjava.banking.PaymentException;
import org.springframework.stereotype.Component;@Component
public class LocalPaymentCreator implements PaymentCreator {// hard coded account value for demo purposesprivate static final String CURRENT_LOCAL_ACC = "current-local-acc";@Overridepublic Payment createPayment(Invoice invoice) throws PaymentException {if (null == invoice.getAccount()) {throw new PaymentException("Account can not be empty when creating local payment!");}return new Payment(CURRENT_LOCAL_ACC, invoice.getAccount(), invoice.getDollars());}}

另一个创建者将是ForeignPaymentCreator ,它具有相当简单的实现:

package com.vrtoonjava.invoices;import com.vrtoonjava.banking.Payment;
import com.vrtoonjava.banking.PaymentCreator;
import com.vrtoonjava.banking.PaymentException;
import org.springframework.stereotype.Component;@Component
public class ForeignPaymentCreator implements PaymentCreator {// hard coded account value for demo purposesprivate static final String CURRENT_IBAN_ACC = "current-iban-acc";@Overridepublic Payment createPayment(Invoice invoice) throws PaymentException {if (null == invoice.getIban()) {throw new PaymentException("IBAN mustn't be null when creating foreign payment!");}return new Payment(CURRENT_IBAN_ACC, invoice.getIban(), invoice.getDollars());}}

这两个创建者是简单的Spring bean,而Apache Camel提供了一种将它们连接到路由的非常好的方法。 我们将在Camel的Java DSL上使用transform()方法创建两个转换器。 我们将正确的转换器插入seda:foreignInvoicesChannel seda:localInvoicesChannelseda:foreignInvoicesChannel seda:localInvoicesChannel ,并使它们将结果转发到seda:bankingChannel 。 将以下代码添加到您的configure方法中:

from("seda:foreignInvoicesChannel").transform().method("foreignPaymentCreator", "createPayment").to("seda:bankingChannel");from("seda:localInvoicesChannel").transform().method("localPaymentCreator", "createPayment").to("seda:bankingChannel");

6.将付款转至银行服务(服务激活器)

付款已经准备就绪,包含付款的消息正在seda:bankingChannel中等待。 该流程的最后一步是使用Service Activator组件。 它的工作方式很简单-当频道中出现新消息时,Apache Camel会调用Service Activator组件中指定的逻辑。 换句话说,我们正在将外部服务连接到我们现有的消息传递基础结构。
为此,我们首先需要查看银行服务合同。 因此,将BankingService接口BankingServicebanking程序包中(在现实世界中,它可能驻留在某些外部模块中):

package com.vrtoonjava.banking;/*** Contract for communication with bank.*/
public interface BankingService {void pay(Payment payment) throws PaymentException;}

现在,我们将需要BankingService的实际实现。 同样,实现不太可能驻留在我们的项目中(它可能是远程公开的服务),但是至少出于教程目的,让我们创建一些模拟实现。 将MockBankingService类添加到banking包:

package com.vrtoonjava.banking;import org.springframework.stereotype.Service;import java.util.Random;/*** Mock service that simulates some banking behavior.* In real world, we might use some web service or a proxy of real service.*/
@Service
public class MockBankingService implements BankingService {private final Random rand = new Random();@Overridepublic void pay(Payment payment) throws PaymentException {if (rand.nextDouble() > 0.9) {throw new PaymentException("Banking services are offline, try again later!");}System.out.println("Processing payment " + payment);}}

模拟实施会在某些随机情况下(约10%)造成故障。 当然,为了实现更好的解耦,我们不会直接使用它,而是将根据自定义组件在合同(接口)上创建依赖关系。 让我们现在将PaymentProcessor类添加到invoices包中:

package com.vrtoonjava.invoices;import com.vrtoonjava.banking.BankingService;
import com.vrtoonjava.banking.Payment;
import com.vrtoonjava.banking.PaymentException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** Endpoint that picks Payments from the system and dispatches them to the* service provided by bank.*/
@Component
public class PaymentProcessor {@AutowiredBankingService bankingService;public void processPayment(Payment payment) throws PaymentException {bankingService.pay(payment);}}

Apache Camel提供了一种简单的方法,当消息到达特定端点时,如何在任意bean上调用方法( EIP将其描述为服务激活器),方法是在Camel的Java DSL上使用bean()方法:

from("seda:bankingChannel").bean(PaymentProcessor.class, "processPayment");

错误处理

消息传递系统的最大挑战之一是正确识别和处理错误情况。 EAI描述了很多方法,我们将使用Camel的Dead Letter Channel EIP的实现。 死信通道只是另一个通道,当此通道中出现错误消息时,我们可以采取适当的措施。 在现实世界的应用程序中,我们可能会寻求一些重试逻辑或专业报告,在我们的示例教程中,我们将仅打印出错误原因。 让我们修改先前定义的Service Activator并插入errorHandler()组件。 当PaymentProcessor引发异常时,此errorHandler会将引起错误的原始消息转发到Dead Letter Channel:

from("seda:bankingChannel").errorHandler(deadLetterChannel("log:failedPayments")).bean(PaymentProcessor.class, "processPayment");

最后,这是最终的完整路线:

package com.vrtoonjava.routes;import com.vrtoonjava.invoices.LowEnoughAmountPredicate;
import com.vrtoonjava.invoices.PaymentProcessor;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;@Component
public class InvoicesRouteBuilder extends RouteBuilder {@Overridepublic void configure() throws Exception {from("seda:newInvoicesChannel").log(LoggingLevel.INFO, "Invoices processing STARTED").split(body()).to("seda:singleInvoicesChannel");from("seda:singleInvoicesChannel").filter(new LowEnoughAmountPredicate()).to("seda:filteredInvoicesChannel");from("seda:filteredInvoicesChannel").choice().when().simple("${body.isForeign}").to("seda:foreignInvoicesChannel").otherwise().to("seda:localInvoicesChannel");from("seda:foreignInvoicesChannel").transform().method("foreignPaymentCreator", "createPayment").to("seda:bankingChannel");from("seda:localInvoicesChannel").transform().method("localPaymentCreator", "createPayment").to("seda:bankingChannel");from("seda:bankingChannel").errorHandler(deadLetterChannel("log:failedPayments")).bean(PaymentProcessor.class, "processPayment");}}

运行整个事情

现在,我们将创建一个作业(它将以固定的速率)将新发票发送到系统。 它只是一个利用Spring的@Scheduled注释的标准Spring bean。 因此,我们向项目添加一个新类– InvoicesJob

package com.vrtoonjava.invoices;import org.apache.camel.Produce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;@Component
public class InvoicesJob {private int limit = 10; // default value, configurable@AutowiredInvoiceCollectorGateway invoiceCollector;@AutowiredInvoiceGenerator invoiceGenerator;@Scheduled(fixedRate = 4000)public void scheduleInvoicesHandling() {Collection<Invoice> invoices = generateInvoices(limit);System.out.println("\n===========> Sending " + invoices.size() + " invoices to the system");invoiceCollector.collectInvoices(invoices);}// configurable from Injectorpublic void setLimit(int limit) {this.limit = limit;}private Collection<Invoice> generateInvoices(int limit) {List<Invoice> invoices = new ArrayList<>();for (int i = 0; i < limit; i++) {invoices.add(invoiceGenerator.nextInvoice());}return invoices;}
}

Job会(每4秒)调用InvoicesGenerator并将发票转发到Gateway(我们了解的第一个组件)。 为了使其工作,我们还需要InvoicesGenerator类:

package com.vrtoonjava.invoices;import org.springframework.stereotype.Component;import java.math.BigDecimal;
import java.util.Random;/*** Utility class for generating invoices.*/
@Component
public class InvoiceGenerator {private Random rand = new Random();public Invoice nextInvoice() {return new Invoice(rand.nextBoolean() ? iban() : null, address(), account(), dollars());}private BigDecimal dollars() {return new BigDecimal(1 + rand.nextInt(20_000));}private String account() {return "test-account " + rand.nextInt(1000) + 1000;}private String address() {return "Test Street " + rand.nextInt(100) + 1;}private String iban() {return "test-iban-" + rand.nextInt(1000) + 1000;}}

这只是一个简单的模拟功能,可让我们看到系统的运行情况。 在现实世界中,我们不会使用任何生成器,而可能会使用某些公开的服务。

现在,在resources文件夹下创建一个新的spring配置文件– invoices-context.xml并声明组件扫描和任务计划支持:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:task = "http://www.springframework.org/schema/task"xmlns:context = "http://www.springframework.org/schema/context"xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><import resource = "camel-config.xml" /><context:component-scan base-package = "com.vrtoonjava" /><task:executor id = "executor" pool-size="10" /><task:scheduler id = "scheduler" pool-size="10" /><task:annotation-driven executor="executor" scheduler="scheduler" /></beans>

要查看整个运行过程,我们还需要最后一块-标准Java主应用程序,我们将在其中创建Spring的ApplicationContext。

package com.vrtoonjava.invoices;import org.springframework.context.support.ClassPathXmlApplicationContext;/*** Entry point of the application.* Creates Spring context, lets Spring to schedule job and use schema.*/
public class InvoicesApplication {public static void main(String[] args) {new ClassPathXmlApplicationContext("/invoices-context.xml");}}

只需从命令行运行mvn clean install并在InvoicesApplication类中启动main方法。 您应该能够看到类似的输出:

===========> Sending 10 invoices to the system
13:48:54.347 INFO  [Camel (camel-1) thread #0 - seda://newInvoicesChannel][route1] Invoices processing STARTED
Amount of $4201 can be automatically processed by system
Amount of $15110 can not be automatically processed by system
Amount of $17165 can not be automatically processed by system
Amount of $1193 can be automatically processed by system
Amount of $6077 can be automatically processed by system
Amount of $17164 can not be automatically processed by system
Amount of $11272 can not be automatically processed by system
Processing payment Payment{senderAccount=current-local-acc, receiverAccount=test-account 1901000, dollars=4201}
Amount of $3598 can be automatically processed by system
Amount of $14449 can not be automatically processed by system
Processing payment Payment{senderAccount=current-local-acc, receiverAccount=test-account 8911000, dollars=1193}
Amount of $12486 can not be automatically processed by system
13:48:54.365 INFO  [Camel (camel-1) thread #5 - seda://bankingChannel][failedPayments] Exchange[ExchangePattern: InOnly, BodyType: com.vrtoonjava.banking.Payment, Body: Payment{senderAccount=current-iban-acc, receiverAccount=test-iban-7451000, dollars=6077}]
Processing payment Payment{senderAccount=current-iban-acc, receiverAccount=test-iban-6201000, dollars=3598}
参考: Apache Camel –在vrtoonjava博客上从JCG合作伙伴 Michal Vrtiak 从头开始开发应用程序(第2部分/第2部分) 。

翻译自: https://www.javacodegeeks.com/2013/11/apache-camel-developing-application-from-the-scratch-part-2-2.html

apache camel

apache camel_Apache Camel –从头开始开发应用程序(第2部分/第2部分)相关推荐

  1. apache camel_Apache Camel –从头开始开发应用程序(第1部分/第2部分)

    apache camel 开始之前 前段时间,我写了一篇关于Spring Integration的教程,以演示如何在受现实发票处理系统启发的示例应用程序中使用Spring Integration. 我 ...

  2. Apache Camel –从头开始开发应用程序(第1部分/第2部分)

    开始之前 前一段时间,我写了一篇关于Spring Integration的教程,以演示如何在受现实发票处理系统启发的示例应用程序中使用Spring Integration. 我对此非常满意,因此我决定 ...

  3. Apache Camel –从头开始开发应用程序(第2部分/第2部分)

    这是本教程的第二部分,我们将使用Apache Camel创建发票处理应用程序. 如果您错过了它,一定要看一下第一部分 . 以前,我们已经定义了系统的功能要求,创建了网关,分离器,过滤器和基于内容的路由 ...

  4. apache camel_Apache Camel日志组件示例

    apache camel Apache Camel日志组件示例 您要将消息记录到底层的记录机制中,请使用骆驼的log:组件. Camel使用sfl4j作为记录器API,然后允许您配置记录器实现. 在本 ...

  5. apache.camel_Apache Camel 2.9发布–十大变化

    apache.camel 在2011年的最后一天,阿帕奇骆驼制品被成功地推到了Maven仓库中,距离香槟酒瓶破裂并进入2012年仅1.5个小时. 2.9版是创纪录的发行版,自5个月前发布2.8版以来, ...

  6. apache.camel_Apache Camel K 1.0在这里–您为什么要关心

    apache.camel 昨天我们发布了Apache Camel K 1.0,并在社交媒体和Camel网站上宣布了该版本. 那么,骆驼K是什么,为什么你要在乎呢? 这是一个很好的问题,我想通过提及伟大 ...

  7. apache.camel_Apache Camel 3.1 – XML路由的快速加载

    apache.camel Camel 3.1中添加的一项功能是能够更快地加载XML路由. 这是我们为使Camel变得更小,更快而进行的总体工作的一部分. 您可能会说ewww XML. 但坦率地说,有很 ...

  8. apache.camel_Apache Camel 3.2 – Camel的无反射配置

    apache.camel 在Apache Camel项目中,我们正在努力开发下一个即将发布的Apache Camel 3.2.0版本. 我们在Camel 3中努力研究的问题之一就是使其变得更小,更快. ...

  9. apache.camel_Apache Camel 3.1 –更多骆驼核心优化(第2部分)

    apache.camel 我以前曾在博客中介绍我们在下一个Camel 3.1版本(第1部分)中所做的优化 . 今天,我想发布大约4周后的状态更新. 我们集中在三个方面优化骆驼核心: 不必要的对象分配 ...

最新文章

  1. iOS 后台下载及管理库
  2. 如何用python画圆形的代码-Python实现的圆形绘制(画圆)示例
  3. mysql 数据库编译安装_mysql 数据库 编译安装(千峰)
  4. Cython屏蔽GIL锁实践
  5. JVM内存管理机制和垃圾回收机制
  6. #pragma code_seg(INIT)/code_seg(PAGE)
  7. Redis的安装过程步骤
  8. redis java eval_【宇润日常疯测-002】Redis-eval() 到底好在哪
  9. TFC2017 腾讯Web前端大会参会小结
  10. B站莫烦Python基础学习笔记
  11. RRT算法原理和代码详解(快速扩展随机树)
  12. .pos文件打开方式
  13. Infopath2007表单转化成word2007
  14. Lisa新歌破吉尼斯世界纪录,MV播放量7460万,中国粉丝贡献大
  15. 抖音终于活成了自己讨厌的样子
  16. 解决ps默认打开显卡的设置
  17. 七牛云 -数据的增加和删除(vue+egg+element-ui+axios)
  18. 实战 | 手把手教你用Python+OpenCV实现滑块验证码->自动拖动验证
  19. Kettle源码本地编译运行
  20. golang小案例 —— 剪子剪子包袱锤小游戏

热门文章

  1. 【动态规划】数字金字塔
  2. 动态规划训练17 [Super Jumping! Jumping! Jumping! HDU - 1087 ]
  3. jstl中添加自定义的函数
  4. vue cli 4.x打包后如何部署到tomcat服务器上
  5. javaWeb服务详解【客户端调用】(含源代码,测试通过,注释) ——测试
  6. java实现打印等腰三角形
  7. Servlet 流程控制
  8. python爬新闻并保存csv_用python爬取内容怎么存入 csv 文件中
  9. internet地址java表示
  10. java集合——数组列表(ArrayList)+散列集(HashSet)