【翻译】Spring Integration参考手册-第二章
2010-8-27
2. 消息结构
Spring Integration中的Message是一个通用的数据容器,可以提供任何对象作为负载(payload),任何Message也可以包含一些带有用户扩展属性键值对的头部。
2.1 消息接口
下面是Message的接口定义:
public interface Message<T> {
T getPayload();
MessageHeaders getHeaders();
}
很明显,Message是一个非常重要的API。通过一个通用的包装封装数据,消息系统可以传递它到各处,而无需知道数据的类型。为一个新应用解决了添加各种新类型,或者当类型可以修改或(和)扩展,消息系统将不会被这些更改影响。另一方面,当消息系统中的一些组件需要访问Message中的信息,一些元数据可以从Message头中存取。
2.2 消息头
正如Spring Integration允许任何对象作为Message的负载,它也支持任何对象类型作为消息头值。事实上,MessageHeaders类实现了java.util.Map接口:
public final class MessageHeaders implements Map<String, Object>, Serializable {
...
}
注意:
尽管MessageHeaders实现了Map,它却是一个只读的实现。任何试图put一个值到Map的操作都会抛出一个UnsupportedOperationException异常。remove和clear操作也是一样的。因为Message可以被传递给多个消费者,所以Map的结构不能被修改。并且,Message负载对象在创建以后不能被set。However, the mutability of the header values themselves (or the payload Object) is intentionally left as a decision for the framework user.
作为Map的一个实现,通过调用get方法,传递消息头的名称作为参数,即可以获取相应的消息头。另外,可以提供一个Class类型的第二个参数。更甚至于,对于获取预定义的值,可以使用非常方便的getter。如下是上面三种情形的示例:
Object someValue = message.getHeaders().get("someKey");
CustomerId customerId = message.getHeaders().get("customerId", CustomerId.class);
Long timestamp = message.getHeaders().getTimestamp();
如下是预定义的消息头:
Table 2.1. Pre-defined Message Headers
Header Name |
Header Type |
ID |
java.util.UUID |
TIMESTAMP |
java.lang.Long |
EXPIRATION_DATE |
java.lang.Long |
CORRELATION_ID |
java.lang.Object |
REPLY_CHANNEL |
java.lang.Object (can be a String or MessageChannel) |
ERROR_CHANNEL |
java.lang.Object (can be a String or MessageChannel) |
SEQUENCE_NUMBER |
java.lang.Integer |
SEQUENCE_SIZE |
java.lang.Integer |
PRIORITY |
MessagePriority (an enum) |
很多inbound和outbound的adapter实现也提供或(和)期望适当的消息头,当然也可以配置额外的用户自定义消息头。
2.3 消息实现
Message接口的基本实现是GenericMessage<T>,他提供了两个构造器:
new GenericMessage<T>(T payload);
new GenericMessage<T>(T payload, Map<String, Object> headers)
创建一个Message时,会同时生成一个随即的唯一ID。构造器可以接受一个消息头的Map,然后复制其中的消息头到新创建的Message。
还有两个方便的子类可用:StringMessage和ErrorMessage。前者接受一个String作为负载:
StringMessage message = new StringMessage("hello world");
String s = message.getPayload();
后者接受任何Throwable对象作为负载:
ErrorMessage message = new ErrorMessage(someThrowable);
Throwable t = message.getPayload();
注意到这些实现得益于GenericMessage类是参数化的。因此,正如上面的示例,从消息中获取负载对象不需要显示的转换类型。
2.4 MessageBuilderHelper类
你可以注意到Message接口只定义了获取消息负载和消息头的方法,却没有setter。这是因为消息创建后就不能被修改。因此,当一个消息的实例发送给多个消费者(例如通过一个发布订阅通道),如果消费者之一需要使用不同的负载类型发送一个响应,它应该创建一个新的Message。所以,这些变动不会影响其他消费者。记住,多个消费者可以访问同样的消息负载实例和消息头,这样的一个实例是否不可修改取决于开发者。换句话说,Message的契约就像是一个不可修改的集合(unmodifiable Collection),而MessageHeaders的map进一步展示了这一点。虽然MessageHeaders类实现了java.util.Map,但是MessageHeaders上任何一个put(或是remove、clear)操作的调用都会产生一个UnsupportedOperationException异常。
相对于需要创建并填充一个Map然后传递给GenericMessage的构造函数来创建消息,Spring Integration提供了一个更方便的方式:MessageBuilder。MessageBuilder提供了两个工厂方法从一个已经存在的消息或是一个负载对象来构造消息实例。当从一个已经存在的消息构建时,
原有消息的负载和消息头都会被复制到新的消息:
Message<String> message1 = MessageBuilder.withPayload("test")
.setHeader("foo", "bar")
.build();
Message<String> message2 = MessageBuilder.fromMessage(message1).build();
assertEquals("test", message2.getPayload());
assertEquals("bar", message2.getHeaders().get("foo"));
如果需要使用一个新的负载来创建一个消息,但是仍然希望从已经存在的消息复制消息头,你可以使用MessageBuilder的copy方法之一。
Message<String> message3 = MessageBuilder.withPayload("test3")
.copyHeaders(message1.getHeaders())
.build();
Message<String> message4 = MessageBuilder.withPayload("test4")
.setHeader("foo", 123)
.copyHeadersIfAbsent(message1.getHeaders())
.build();
assertEquals("bar", message3.getHeaders().get("foo"));
assertEquals(123, message4.getHeaders().get("foo"));
注意copyHeadersIfAbsent不会覆盖现有的值。在上面的第二个例子中,你也可以看到如何使用setHeader设置用户自定义的消息头。最后,系统提供了一些方法来设置一些预定义的消息头,它们不会妨碍设置任何消息头(MessageHeaders类中也定义了这些预定义消息头名字的常量)。
Message<Integer> importantMessage = MessageBuilder.withPayload(99)
.setPriority(MessagePriority.HIGHEST)
.build();
assertEquals(MessagePriority.HIGHEST, importantMessage.getHeaders().getPriority());
Message<Integer> anotherMessage = MessageBuilder.fromMessage(importantMessage)
.setHeaderIfAbsent(MessageHeaders.PRIORITY, MessagePriority.LOW)
.build();
assertEquals(MessagePriority.HIGHEST, anotherMessage.getHeaders().getPriority());
MessagePrioity是仅仅在使用PrioityChannel时被考虑(将在下一章描述)。它被定义成一个包括5个可能的值的枚举量。
public enum MessagePriority {
HIGHEST,
HIGH,
NORMAL,
LOW,
LOWEST
}
上一篇: 91期百淘感想-创世记
下一篇: 链栈与链队列