错误处理在Spring Integration中如何工作

1.引言

这篇文章的目标是向您展示将消息传递系统与Spring Integration结合使用时如何处理错误。 您将看到同步和异步消息传递之间的错误处理有所不同。 和往常一样,我将跳过聊天并继续进行一些示例。

  • 您可以在github上获取源代码。

2,样品申请

我将使用一个基本示例,因为我想专注于异常处理。 该应用程序包含一个订单服务,该服务接收订单,处理订单并返回确认。

下面我们可以看到消息传递系统的配置方式:

int-config.xml

<context:component-scan base-package="xpadro.spring.integration"/><int:gateway default-request-channel="requestChannel" service-interface="xpadro.spring.integration.service.OrderService"/><int:channel id="requestChannel"/><int:router input-channel="requestChannel" ref="orderRouter" method="redirectOrder"/><int:channel id="syncChannel"/><int:channel id="asyncChannel"><int:queue capacity="5"/>
</int:channel><int:service-activator method="processOrder" input-channel="syncChannel" ref="orderProcessor"/><int:service-activator method="processOrder" input-channel="asyncChannel" ref="orderProcessor"><int:poller fixed-delay="2000"/>
</int:service-activator>

网关是消息传递系统的入口点。 它将接收订单并将其发送到直接通道“ requestChannel”,路由器将根据订单ID将其重定向到适当的通道:

  • syncChannel:一个直接通道 ,它将订单发送到订阅该通道的订单处理器。
  • asyncChannel:一个队列通道 ,订单处理器将从中主动检索订单。

处理订单后,订单确认将发送回网关。 这是代表此的图形:

嫁接

好的,让我们从最简单的情况开始,使用直接通道进行同步发送。

3.与直接通道同步发送

订单处理器已订阅“ syncChannel”直接渠道。 “ processOrder”方法将在发送者的线程中调用。

public OrderConfirmation processOrder(Order order) {logger.info("Processing order {}", order.getId());if (isInvalidOrder(order)) {logger.info("Error while processing order [{}]", ERROR_INVALID_ID);throw new InvalidOrderException(ERROR_INVALID_ID);}return new OrderConfirmation("confirmed");
}

现在,我们将执行一个测试,该测试将通过发送无效订单来引发异常。 此测试将向网关发送订单:

public interface OrderService {@Gatewaypublic OrderConfirmation sendOrder(Order order);
}

考试:

TestSyncErrorHandling.java

@ContextConfiguration(locations = {"/xpadro/spring/integration/config/int-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class TestSyncErrorHandling {@Autowiredprivate OrderService service;@Testpublic void testCorrectOrder() {OrderConfirmation confirmation = service.sendOrder(new Order(3, "a correct order"));Assert.assertNotNull(confirmation);Assert.assertEquals("confirmed", confirmation.getId());}@Testpublic void testSyncErrorHandling() {OrderConfirmation confirmation = null;try {confirmation = service.sendOrder(new Order(1, "an invalid order"));Assert.fail("Should throw a MessageHandlingException");} catch (MessageHandlingException e) {Assert.assertEquals(InvalidOrderException.class, e.getCause().getClass());Assert.assertNull(confirmation);}}
}

我们运行测试,看看在订单处理器中如何引发异常并到达测试。 没关系; 我们想验证发送无效订单是否引发了异常。 发生这种情况是因为测试发送了订单,并阻止等待在同一线程中处理订单。 但是,当我们使用异步通道时会发生什么? 让我们继续下一节。

4,与队列通道异步发送

此部分的测试发送一个命令,该命令将由路由器重定向到队列通道。 网关如下所示:

public interface OrderService {@Gatewaypublic Future<OrderConfirmation> sendFutureOrder(Order order);
}

请注意,这次网关正在返回Future 。 如果我们不返回此值,则网关将阻止测试线程。 通过返回Future,网关将变为异步状态,并且不会阻塞发送方的线程。

考试:

TestKoAsyncErrorHandling.java

@ContextConfiguration(locations = {"/xpadro/spring/integration/config/int-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class TestKoAsyncErrorHandling {@Autowiredprivate OrderService service;@Test(expected=MessageHandlingException.class)public void testAsyncErrorHandling() throws InterruptedException, ExecutionException {Future<OrderConfirmation> confirmation = service.sendFutureOrder(new Order(6, "another order"));}
}

好的,现在我们将启动测试并看到引发异常的信息…

java.lang.AssertionError: Expected exception: org.springframework.integration.MessageHandlingException

糟糕,测试失败,因为没有异常到达测试! 发生了什么? 好吧,解释如下:

<int:channel id="asyncChannel"><int:queue capacity="5"/>
</int:channel><int:service-activator method="processOrder" input-channel="asyncChannel" ref="orderProcessor"><int:poller fixed-delay="2000"/>
</int:service-activator>

由于我们使用的是异步通道(队列),因此发送者发送订单并继续前进。 然后,接收方从另一个线程轮询订单。 因此,不可能将Exception抛回到发送方。 让我们表现得好像什么都没发生吗? 好吧,您最好不要,还有其他选择。

5,异步错误处理

当使用异步消息传递时,Spring Integration通过将异常发布到消息通道来处理它们。 引发的异常将包装到MessagingException中,并成为消息的有效负载。

错误消息发送到哪个通道? 首先,它将检查请求消息是否包含名为“ errorChannel”的标头。 如果找到,错误消息将被发送到那里。 否则,该消息将被发送到所谓的全局错误通道。

5.1全局错误通道

默认情况下,Spring Integration创建一个名为“ errorChannel”的全局错误通道。 该频道是发布-订阅频道。 这意味着我们可以为该频道订阅多个端点。 实际上,已经有一个端点订阅了它:一个日志记录处理程序 。该处理程序将记录到达通道的消息的有效负载,尽管可以将其配置为不同的行为。

现在,我们将向该全局通道订阅一个新的处理程序,并通过将其存储到数据库中来测试它是否接收到异常消息。

首先,我们需要在配置中进行一些更改。 我创建了一个新文件,因此它不会干扰我们之前的测试:

int-async-config.xml

<context:component-scan base-package="xpadro.spring.integration"/><int:gateway default-request-channel="asyncChannel" service-interface="xpadro.spring.integration.service.OrderService" error-channel="errorChannel"/><int:channel id="asyncChannel"><int:queue capacity="5"/>
</int:channel><int:service-activator method="processOrder" input-channel="asyncChannel" ref="orderProcessor"><int:poller fixed-delay="2000"/>
</int:service-activator><int:service-activator input-channel="errorChannel" ref="orderErrorHandler" method="handleFailedOrder"/><bean id="orderErrorHandler" class="xpadro.spring.integration.activator.OrderErrorHandler"/>

网关 :我添加了一个错误通道。 如果调用失败,错误消息将发送到该通道。 如果我没有定义错误通道,则网关会将异常传播给调用者,但是在这种情况下,由于这是一个异步网关,因此无法正常工作。

错误处理程序 :我已经定义了一个新的端点,该端点已订阅了全局错误通道。 现在,任何发送到全局错误通道的错误消息都将传递给我们的处理程序。

我还添加了一个配置文件以配置数据库。 我们的错误处理程序会将收到的错误插入此数据库:

db-config.xml

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><constructor-arg ref="dataSource"/>
</bean><!-- in-memory database -->
<jdbc:embedded-database id="dataSource"><jdbc:script location="classpath:db/schemas/schema.sql" />
</jdbc:embedded-database>

错误处理程序非常简单。 它收到错误消息,并将其信息插入数据库:

public class OrderErrorHandler {@Autowiredprivate JdbcTemplate jdbcTemplate;@ServiceActivatorpublic void handleFailedOrder(Message<MessageHandlingException> message) {Order requestedOrder = (Order) message.getPayload().getFailedMessage().getPayload();saveToBD(requestedOrder.getId(), message.getPayload().getMessage());}private void saveToBD(int orderId, String errorMessage) {String query = "insert into errors(orderid, message) values (?,?)";jdbcTemplate.update(query, orderId, errorMessage);}
}

好的,现在一切就绪。 让我们实施一个新的测试:

TestOkAsyncErrorHandlingTest.java

@ContextConfiguration(locations = {"/xpadro/spring/integration/config/int-async-config.xml","/xpadro/spring/integration/config/db-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class TestOkAsyncErrorHandling {@Autowiredprivate JdbcTemplate jdbcTemplate;@Autowiredprivate OrderService service;@Beforepublic void prepareTest() {jdbcTemplate.update("delete from errors");}@Testpublic void testCorrectOrder() throws InterruptedException, ExecutionException {Future<OrderConfirmation> confirmation = service.sendFutureOrder(new Order(7, "another correct order"));OrderConfirmation orderConfirmation = confirmation.get();Assert.assertNotNull(orderConfirmation);Assert.assertEquals("confirmed", orderConfirmation.getId());}@Testpublic void testAsyncErrorHandling() throws InterruptedException, ExecutionException {Future<OrderConfirmation> confirmation = service.sendFutureOrder(new Order(6, "another order"));Thread.sleep(2000);Assert.assertEquals(1, getSavedErrors());validateSavedError(6);}private int getSavedErrors() {return jdbcTemplate.queryForObject("select count(*) from errors", Integer.class);}private void validateSavedError(int orderId) {String query = "select * from errors where orderid=?";Map<String, Object> result = jdbcTemplate.queryForMap(query, orderId);Assert.assertEquals(6, result.get("orderid"));assertThat((String)result.get("message"), containsString("Order ID is invalid"));}
}

这次测试成功,错误消息已存储到数据库。

5.2其他机制

自定义错误通道 :您可以定义错误通道并将其定义为队列通道,而不是默认的发布-订阅通道:

<int:poller id="defaultPoller" default="true" fixed-delay="5000" /><int:channel id="errorChannel"><int:queue capacity="10"/>
</int:channel>

ErrorMessageExceptionTypeRouter :这个Spring Integration专用路由器将解析将错误消息发送到的通道。 它基于错误的最具体原因做出决定:

<int:exception-type-router input-channel="errorChannel" default-output-channel="genericErrorChannel"><int:mapping exception-type="xpadro.spring.integration.exception.InvalidOrderException" channel="invalidChannel" /><int:mapping exception-type="xpadro.spring.integration.exception.FooException" channel="fooChannel" />
</int:exception-type-router>

六,结论

我们已经了解了使用Spring Integration时错误处理的不同机制是什么。 有了这个基础,您将能够通过实现转换器从错误消息中提取信息,使用标头扩展器设置错误通道或实现自己的路由器等来扩展它并配置错误处理。

参考:来自XavierPadró博客博客的JCG合作伙伴 Xavier Padro 在Spring Integration中如何处理错误 。

翻译自: https://www.javacodegeeks.com/2014/02/how-error-handling-works-in-spring-integration.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/364724.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

原生js、jQuery实现选项卡功能

在大家在网上平常浏览网页的时候&#xff0c;想必各位都会看到选项卡功能&#xff0c;在这里给大家详解一下用原生js、jQuery如何来写一些基本的选项卡 话不多说&#xff0c;先给各位看一下功能图&#xff1a; 好了&#xff0c;下边开始写代码了&#xff1a; HTML代码&#x…

.NET core2.0 发布至IIS中

.NET CORE和asp.net 发布时不太一样&#xff0c;ASP.NET Core不再是由IIS工作进程&#xff08;w3wp.exe&#xff09;托管&#xff0c;而是使用自托管Web服务器&#xff08;Kestrel&#xff09;运行&#xff0c;IIS则是作为反向代理的角色转发请求到Kestrel不同端口的ASP.NET Co…

深入了解Java 8日期和时间API

在这篇文章中&#xff0c;我们将更深入地了解通过Java 8获得的新的Date / Time API&#xff08; JSR 310 &#xff09;。 请注意&#xff0c;本文主要由显示新API功能的代码示例驱动。 我认为这些示例是不言自明的&#xff0c;因此我没有花太多时间在它们周围写文本:-) 让我们…

P4047 部落划分

这题太水了吧&#xff0c;不知道怎么蓝的&#xff0c;蒟蒻只写了十五分钟就一次AC了…… 但是挺有意思&#xff0c;就发篇题解吧qwq emmm……最小生成树&#xff08;贪心&#xff09;&#xff0c;就没别的了…… 要明确&#xff1a; 一开始可以把每个点都看成一个部落&#xff…

如何用纯 CSS 创作一个文本淡入淡出的 loader 动画

效果预览 在线演示 按下右侧的“点击预览”按钮可以在当前页面预览&#xff0c;点击链接可以全屏预览。https://codepen.io/comehope/pen/ERwpeG可交互视频此视频是可以交互的&#xff0c;你可以随时暂停视频&#xff0c;编辑视频中的代码。请用 chrome, safari, edge 打开观…

java csf_WebService CSF使用详解 | 学步园

一建立service:1)CxfService&#xff1a;WebServicepublicinterfaceCxfService {WebMethodpublicWebResultList getTasksByActor(WebParam(name"actor") String actor);WebMethodpublicvoidcreateAndStartProcessInstance(WebParam(name"processName") Str…

软件工程和项目管理的区别

软件工程的定义&#xff1a; 软件工程是研究和应用如何以系统性的、规范化的、可定量的过程化方法去开发和维护软件&#xff0c;以及如何把经过时间考验而证明正确的管理技术和当前能够得到的最好的技术方法结合起来。 项目管理的定义&#xff1a; 项目管理是一个管理学分支的学…

如何启动多个WebLogic托管服务器

WebLogic Server文档建议您创建专用的管理服务器&#xff0c;然后分离托管服务器以进行应用程序部署。 在这里&#xff0c;我将向您展示如何在与管理服务器相同的主机中创建一个或多个托管服务器。 我假设您已经安装了WLS&#xff0c;并已创建并正在运行自己的域。 如果您以前…

《机器学习基石》第一周 —— When Can Machine Learn?

&#xff08;注&#xff1a;由于之前进行了吴恩达机器学习课程的学习&#xff0c;其中有部分内容与机器学习基石的内容重叠&#xff0c;所以以下该系列的笔记只记录新的知识&#xff09; 《机器学习基石》课程围绕着下面这四个问题而展开&#xff1a; 主要内容&#xff1a; 一、…

如何用纯 CSS 创作一盘传统蚊香

效果预览 在线演示 按下右侧的“点击预览”按钮可以在当前页面预览&#xff0c;点击链接可以全屏预览。https://codepen.io/comehope/pen/BVpvMz可交互视频教程此视频是可以交互的&#xff0c;你可以随时暂停视频&#xff0c;编辑视频中的代码。请用 chrome, safari, edge 打…

LeetCode 905. 按奇偶排序数组

LeetCode 905. 按奇偶排序数组 转载于:https://www.cnblogs.com/hglibin/p/10794792.html

java父类序列化_父类的序列化与 Transient 关键字

情境&#xff1a;一个子类实现了 Serializable 接口&#xff0c;它的父类都没有实现 Serializable 接口&#xff0c;序列化该子类对象&#xff0c;然后反序列化后输出父类定义的某变量的数值&#xff0c;该变量数值与序列化时的数值不同。解决&#xff1a;要想将父类对象也序列…

Java:在Runnable中处理RuntimeException

去年年底&#xff0c;我正在运行预定的任务来监视Neo4j集群&#xff0c;而我遇到的问题之一是有时监视会退出。 我最终意识到这是因为RuntimeException被抛出到Runnable方法中&#xff0c;而我没有处理它。 以下代码演示了该问题&#xff1a; import java.util.ArrayList; im…

错误代码: 1231 - Variable 'sql_mode' can't be set to the value of 'NULL'

错误代码&#xff1a; 1231 - Variable sql_mode cant be set to the value of NULL 错误代码&#xff1a; 1231 - Variable sql_mode cant be set to the value of NULL 错误代码&#xff1a; 1231 - Variable sql_mode cant be set to the value of NULL mysql中的提示 删除注…

[Unity3D]Unity3D游戏开发之怪物AI

大家好。欢迎大家关注由我为大家带来的Unity3D游戏开发系列文章&#xff0c;我的博客地址为&#xff1a;http://blog.csdn.net/qinyuanpei。在上一篇文章中&#xff0c;我们基本上实现了一个小地图的功能&#xff0c;今天呢&#xff0c;我们来实现怪物AI&#xff0c;所谓怪物AI…

中国第一批写java的人_中国java开源界最可爱的人们

评论# re: 中国java开源界最可爱的人们2007-12-07 15:29sitinspring如果少一些抒情,多一点实质内容,文章更耐看. 回复 更多评论# re: 中国java开源界最可爱的人们[未登录]2007-12-07 15:49dennis竟然没有满江红&#xff0c;opendoc的意义不用多说了吧 回复 更多评论# re: 中…

如何把握好 transition 和 animation 的时序,创作描边按钮特效

效果预览 在线演示 按下右侧的“点击预览”按钮可以在当前页面预览&#xff0c;点击链接可以全屏预览。https://codepen.io/comehope/pen/mKdzZM可交互视频教程此视频是可以交互的&#xff0c;你可以随时暂停视频&#xff0c;编辑视频中的代码。请用 chrome, safari, edge 打…

使用PHREAK算法实现Drools 6性能

Drools 6引入了新的惰性匹配算法。 该算法的详细信息已在之前的两个博客中介绍&#xff1a; RIP RETE时间获得PHREAKY 基于PHREAK堆栈的评估和向后链接 第一篇文章讨论了性能以及为什么算法的批处理和惰性方面难以比较。 “性能的最后一点。 通常&#xff0c;使用PHREAK的单…

02Data

1.数据从何而来 2.数据对象和属性类型 数据集合的类型 结构数据的重要特征 数据对象 属性 属性类型 数据属性的类型 离散 vs.连续属性 3.数据的&#xff08;基本&#xff09;统计描述 分布度量 代数度量 整体度量 度量数据的中心趋势 对称/偏斜数据 4.数据可视化 5.数据的相似…

PAT 1131 Subway Map

题目链接&#xff1a; https://pintia.cn/problem-sets/994805342720868352/problems/994805347523346432 思路&#xff1a; 说多了都是泪&#xff0c; Dijstra超时&#xff0c;采用dfs 利用map<pair<int,int>,int>&#xff0c;表示两个点和他们中间的地铁线号 每次…