如何在春季集成中解组其 Xml 有效负载后保留 JMS 标头



我正在使用Jmeter发送带有XML有效负载和一些自定义标头的JMS消息,这些标头contentTypetext/jsontext/xml

我的 Spring 集成配置如下所示:

<jms:message-driven-channel-adapter channel="jmsInChannel" destination-name="queue.demo" connection-factory="jmsConnectionFactory1" />
<int:channel id="jmsInChannel" />
<int:header-value-router input-channel="jmsInChannel" header-name="contentType" default-output-channel="nullChannel">
<int:mapping value="text/json" channel="jsonTransformerChannel" />
<int:mapping value="text/xml" channel="xmlTransformerChannel" />
</int:header-value-router>

到目前为止,一切正常,消息已成功路由到各自的转换器。

我的问题是,当它是一个XML有效载荷时,我首先使用了JAXB解组器以及http://www.springframework.org/schema/integration/xml提供的<ixml:unmarshalling-transofmer ../>

我可以获取有效负载,但它无法将消息作为 JMS 消息处理,它变成了一个纯粹的 POJO。所以我丢失了标头,如果不序列化 POJO,我就无法使用<int: ../>组件,这不是我想要实现的。

我找到了一个解决方法,我在java中定义了自己的解组bean,如下所示:

<int:channel id="xmlTransformerChannel" />
<int:transformer input-channel="xmlTransformerChannel" ref="xmlMsgToCustomerPojoTransformer" output-channel="enrichInChannel" />

方法:

@SuppressWarnings("rawtypes")
public Message transform(String message) {
logger.info("Message Received rn" + message);
try {
MyModel myModel = (MyModel) unmarshaller.unmarshal(new StreamSource(new StringReader(message)));
return MessageBuilder.withPayload(myModel).build();
} catch (XmlMappingException e) {
return MessageBuilder.withPayload(e).build();
} catch (Exception e) {
return MessageBuilder.withPayload(e).build();
}
}

我可以成功地将消息处理为 Spring 集成消息,但我丢失了原始的自定义 JMS 标头。

相比之下,要转换 json 有效负载并保持消息格式并保留我的自定义标头,我所要做的就是以下 xml 配置:

<int:channel id="jsonTransformerChannel" />
<int:json-to-object-transformer input-channel="jsonTransformerChannel" output-channel="enrichInChannel" type="com.alrawas.ig5.MyModel" />

我的问题是,如何在解组 xml 有效负载后保留原始自定义 JMS 标头?

更新:

我确实尝试以这种方式编写 xml 转换器,将 Message 作为输入而不仅仅是字符串,它在此方法中没有抛出异常,但它在路由阶段的后期确实如此

public Message<?> transform(Message<String> message) {
logger.info("Message Received rn" + message);
try {
MyModel myModel = (MyModel) unmarshaller.unmarshal(new StreamSource(new StringReader(message.getPayload())));
return (Message<MyModel>) MessageBuilder.withPayload(myModel).copyHeaders(message.getHeaders()).build();
} catch (XmlMappingException e) {
return MessageBuilder.withPayload(e).build();
} catch (Exception e) {
return MessageBuilder.withPayload(e).build();
}
}

我在此流程后面使用的组件中遇到了问题:

<int:object-to-json-transformer input-channel="outr" output-channel="outch" />
<int:router method="route" input-channel="outch" default-output-channel="nullChannel">
<bean class="com.alrawas.ig5.MyCustomRouter" />
</int:router>

在我的路由方法中抛出无法将字符串转换为com.alrawas.ig5.MyModel异常:

public class MyCustomRouter {
public String route(Message<MyModel> myModel) {
Integer tenNumber = myModel.getPayload().getNumber(); // <-- Cast Exception here
System.out.println(myModel);
return (tenNumber % 10 == 0) ? "stayLocal" : "goRemote";
}
}

此强制转换异常仅在解组 xml 后发生,JSON 有效负载工作正常,不会丢失标头或引发强制转换异常。

更新:

在下面检查我的答案:contentType 并不是一个真正的自定义标头

当您开发自定义transformer时,您需要记住,返回Message<?>会导致您完全控制其内容。

当转换器函数返回一个Message时,它不会填充任何请求标头。

因此,您的public Message transform(String message) {必须期望将Message作为输入,并且您需要复制请求消息中的所有标头以回复消息。MessageBuilder上有适当的方法.

另一方面,完全不清楚为什么需要在这里返回Message,因为 Spring 集成中的所有内容在发送到输出通道之前都将包装到Message

采取:

ClassCastException在上一个路由器的后期发生,因为我将我的自定义标头命名为contentType。这是内部使用的默认 jms 标头。当我将其值更改为text/xml时,最后一个路由器String route(Message<MyModel> myModel)试图将 json 转换为 MyModel,但它失败了,因为标头不再像它应该的那样application/json,它是text/xml的。这导致了 ClassCastException。

所以我摆脱了自定义的 xml 解组逻辑 bean。我重命名了我的自定义标头。并用<ixml:unmarshalling-transformer ../>.

它使用 xml 配置工作,无需额外的自定义 Java bean。

相关内容

最新更新