如何在 spring 集成中解组其 Xml 有效负载后保留 JMS Headers
How to keep JMS Headers after Unmarshalling their Xml payload in spring integration
我正在使用 Jmeter 发送带有 XML 负载和一些自定义 headers contentType
值 text/json
和 text/xml
的 JMS 消息。
我的 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>
到目前为止,一切正常,消息已成功路由到各自的 t运行sformers。
我的问题是,当它是 XML 有效载荷时,我首先使用了 JAXB Unmarshaller 以及 http://www.springframework.org/schema/integration/xml
提供的 <ixml:unmarshalling-transofmer ../>
。
我可以拿到payload,但是之后无法把消息当做JMS消息来处理,变成了纯POJO。所以我丢失了 headers,并且我无法在不序列化 POJO 的情况下使用 <int: ../>
组件,这不是我想要实现的。
我找到了一个 work-around,我在 java 中定义了自己的 Unmarshalling 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 \r\n" + 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 headers。
相比之下,我必须做的就是 运行 形成 json 有效负载并保持消息格式并保留我的自定义 headers 就是这个 xml 配置:
<int:channel id="jsonTransformerChannel" />
<int:json-to-object-transformer input-channel="jsonTransformerChannel" output-channel="enrichInChannel" type="com.alrawas.ig5.MyModel" />
我的问题是,如何在解组 xml 有效负载后保留原始自定义 JMS headers?
更新:
我确实尝试过这样写 xml t运行sformer,将 Message 作为输入而不是字符串,它在这个方法中没有抛出异常,但它在后面的路由阶段
public Message<?> transform(Message<String> message) {
logger.info("Message Received \r\n" + 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 有效载荷工作正常,不会丢失 headers 或抛出转换异常。
更新:
检查下面我的回答:
当您开发自定义 transformer
时,您需要牢记 return 使用 Message<?>
会让您完全控制其内容。
当转换器函数 return 是 Message
时,它不会填充任何请求 headers。
因此,您的 public Message transform(String message) {
必须期望 Message
作为输入,并且您需要将请求消息中的所有 headers 复制到回复消息。 MessageBuilder
.
上有合适的方法
另一方面,完全不清楚为什么您需要在此处 return 一个 Message
,因为 Spring 集成中的所有内容都将包装到 Message
在发送到输出通道之前。
拍摄:
ClassCastException 后来在最后一个路由器中发生,是因为我将我的自定义命名为 header contentType
。这是内部使用的默认 jms header。当我将其值更改为 text/xml
时,最后一个路由器 String route(Message<MyModel> myModel)
试图将 json 转换为 MyModel,但失败了,因为 header 不再是 application/json
应该是 text/xml
。这导致了 ClassCastException。
所以我摆脱了自定义 xml 解组逻辑 bean。我重命名了我的习惯 header。并使用 <ixml:unmarshalling-transformer ../>
.
它使用 xml 配置工作,无需额外的自定义 java bean。
我正在使用 Jmeter 发送带有 XML 负载和一些自定义 headers contentType
值 text/json
和 text/xml
的 JMS 消息。
我的 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>
到目前为止,一切正常,消息已成功路由到各自的 t运行sformers。
我的问题是,当它是 XML 有效载荷时,我首先使用了 JAXB Unmarshaller 以及 http://www.springframework.org/schema/integration/xml
提供的 <ixml:unmarshalling-transofmer ../>
。
我可以拿到payload,但是之后无法把消息当做JMS消息来处理,变成了纯POJO。所以我丢失了 headers,并且我无法在不序列化 POJO 的情况下使用 <int: ../>
组件,这不是我想要实现的。
我找到了一个 work-around,我在 java 中定义了自己的 Unmarshalling 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 \r\n" + 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 headers。
相比之下,我必须做的就是 运行 形成 json 有效负载并保持消息格式并保留我的自定义 headers 就是这个 xml 配置:
<int:channel id="jsonTransformerChannel" />
<int:json-to-object-transformer input-channel="jsonTransformerChannel" output-channel="enrichInChannel" type="com.alrawas.ig5.MyModel" />
我的问题是,如何在解组 xml 有效负载后保留原始自定义 JMS headers?
更新:
我确实尝试过这样写 xml t运行sformer,将 Message 作为输入而不是字符串,它在这个方法中没有抛出异常,但它在后面的路由阶段
public Message<?> transform(Message<String> message) {
logger.info("Message Received \r\n" + 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 有效载荷工作正常,不会丢失 headers 或抛出转换异常。
更新:
检查下面我的回答:
当您开发自定义 transformer
时,您需要牢记 return 使用 Message<?>
会让您完全控制其内容。
当转换器函数 return 是 Message
时,它不会填充任何请求 headers。
因此,您的 public Message transform(String message) {
必须期望 Message
作为输入,并且您需要将请求消息中的所有 headers 复制到回复消息。 MessageBuilder
.
另一方面,完全不清楚为什么您需要在此处 return 一个 Message
,因为 Spring 集成中的所有内容都将包装到 Message
在发送到输出通道之前。
拍摄:
ClassCastException 后来在最后一个路由器中发生,是因为我将我的自定义命名为 header contentType
。这是内部使用的默认 jms header。当我将其值更改为 text/xml
时,最后一个路由器 String route(Message<MyModel> myModel)
试图将 json 转换为 MyModel,但失败了,因为 header 不再是 application/json
应该是 text/xml
。这导致了 ClassCastException。
所以我摆脱了自定义 xml 解组逻辑 bean。我重命名了我的习惯 header。并使用 <ixml:unmarshalling-transformer ../>
.
它使用 xml 配置工作,无需额外的自定义 java bean。