Spring AMQP抽象层

  • AMQP抽象
Spring AMQP包含了很多模块,每一个模块在发布的时候都已一个Jar包的方式提供。这些模块包括:spring-amqp,spring-rabbit,spring-erlang。spring-amqp包含 org.springframework.amqp.core包。在这个包里面你将发现代表着AMQP核心模型的类。我们的意图是提供高度的抽象,这个抽象不会依赖任何一个具体的AMQP代理实现或者客户端实现。每一个用户的代码将游离于不同的实现,因为它是针对抽象层开发的。这些抽象最终会被一些具体的消息代理实现为具体的模块,例如spring-rabbit。由于AMQP的操作是在协议层,所以理论上说,RabbitMQ可以被其他支持同样协议版本的代理使用,但是到目前为止没有进行测试。
  • 消息
AMQP 0-8 0-9-1的规定没有定义Message类和接口。然而,当我们执行诸如‘ basicPublish’的操作,内容将作为字节数组进行传递,附加属性将使用额外的参数进行传递。Spring AMQP定义了消息类,作为更为广泛的AMQP领域模型中的一部分。消息类的目的是简单封装了内容与属性在一个实体中,从而API变得更简单。消息类的定义很直观。
  
  
  1. public class Message implements Serializable {
  2. private static final long serialVersionUID = -7177590352110605597L;
  3. private static final String ENCODING = Charset.defaultCharset().name();
  4. private final MessageProperties messageProperties;
  5. private final byte[] body;
  6. public Message(byte[] body, MessageProperties messageProperties) {
  7. this.body = body;
  8. this.messageProperties = messageProperties;
  9. }
  10. public byte[] getBody() {
  11. return this.body;
  12. }
  13. public MessageProperties getMessageProperties() {
  14. return this.messageProperties;
  15. }
  16. @Override
  17. public String toString() {
  18. StringBuffer buffer = new StringBuffer();
  19. buffer.append("(");
  20. buffer.append("Body:'" + this.getBodyContentAsString() + "'");
  21. if (messageProperties != null) {
  22. buffer.append(messageProperties.toString());
  23. }
  24. buffer.append(")");
  25. return buffer.toString();
  26. }
  27. private String getBodyContentAsString() {
  28. if (body == null) {
  29. return null;
  30. }
  31. try {
  32. String contentType = (messageProperties != null) ? messageProperties.getContentType() : null;
  33. if (MessageProperties.CONTENT_TYPE_SERIALIZED_OBJECT.equals(contentType)) {
  34. return SerializationUtils.deserialize(body).toString();
  35. }
  36. if (MessageProperties.CONTENT_TYPE_TEXT_PLAIN.equals(contentType)
  37. || MessageProperties.CONTENT_TYPE_JSON.equals(contentType)
  38. || MessageProperties.CONTENT_TYPE_JSON_ALT.equals(contentType)
  39. || MessageProperties.CONTENT_TYPE_XML.equals(contentType)) {
  40. return new String(body, ENCODING);
  41. }
  42. }
  43. catch (Exception e) {
  44. // ignore
  45. }
  46. // Comes out as '[B@....b' (so harmless)
  47. return body.toString()+"(byte["+body.length+"])";
  48. }
  49. @Override
  50. public int hashCode() {
  51. final int prime = 31;
  52. int result = 1;
  53. result = prime * result + Arrays.hashCode(body);
  54. result = prime * result + ((messageProperties == null) ? 0 : messageProperties.hashCode());
  55. return result;
  56. }
  57. @Override
  58. public boolean equals(Object obj) {
  59. if (this == obj) {
  60. return true;
  61. }
  62. if (obj == null) {
  63. return false;
  64. }
  65. if (getClass() != obj.getClass()) {
  66. return false;
  67. }
  68. Message other = (Message) obj;
  69. if (!Arrays.equals(body, other.body)) {
  70. return false;
  71. }
  72. if (messageProperties == null) {
  73. if (other.messageProperties != null) {
  74. return false;
  75. }
  76. }
  77. else if (!messageProperties.equals(other.messageProperties)) {
  78. return false;
  79. }
  80. return true;
  81. }
MessageProperties  类中定义了一些公共的属性,例如‘ messageId ’,‘ timestamp ’,‘ contentType ’,这些属性同样可以通过调用方法 setHeader(String key, Object value)   进行扩展。
  • 交换
Exchange  接口代表一个AMQP  Exchange,它是消息生产者消息所发送到的地方,一个消息代理中的虚拟主中的每一个Exchange的名称必须唯一,它还有其他一些属性。
   
   
  1. public interface Exchange {
  2. String getName();
  3. String getExchangeType();
  4. boolean isDurable();
  5. boolean isAutoDelete();
  6. Map<String, Object> getArguments();
  7. }
可以看到,Exchange有一个类型'type',这个类型在ExchangeTypes中定义。基本的类型包括:Direct,Topic,Fanout,和Headers。在核心包中你会发现Exchange接口针对每一种类型的实现。这些不同类型的Exchange因为它们处理队列绑定的方式不一样而不同。例如,Direct Exchange允许通过固定的路由键来和队列进行绑定。Topic Exchange支持通过'*' '#'通配符分别代表一个或者零个或者多个进行绑定。Fanout  Exchange将不考虑路由键,将消息发送到绑定的所有队列中。
AMQP规范要求任何一个消息代理必须提供一个’default‘ Direct Exchange,这个Exchange没有名称。所有声明的队列都和这个Exchange绑定,使用它们的名称作为路由键。
  • 队列
队列类存储着消息的组件,消息消费者从队列中接收到消息。
   
   
  1. public class Queue {
  2. private final String name;
  3. private volatile boolean durable;
  4. private volatile boolean exclusive;
  5. private volatile boolean autoDelete;
  6. private volatile Map<String, Object> arguments;
  7. /**
  8. * The queue is durable, non-exclusive and non auto-delete.
  9. *
  10. * @param name the name of the queue.
  11. */
  12. public Queue(String name) {
  13. this(name, true, false, false);
  14. }
  15. // Getters and Setters omitted for brevity
注意构造函数接收队列的名称。取决于具体的实现,admin模板提供了方法来产生唯一名称的队列。像这类的队列可以作为’reply-to'地址或者一些临时的场景。由于这些原因,自动产生的队列的‘exclusive’和‘autoDelete’属性通常被设置为true。

  • 绑定
我们知道生产者发送消息给到一个Exchange,消费者从队列中取到消息,队列和Exchange之间的绑定至关重要,它们通过消息来连接着生产者和消费者。在Spring AMQP中我们使用Binding这个类来代表这层连接关系。下面我们来看看Queue和Exchange之间的绑定:
Queue和DirectExchange之间通过国定的路由键进行绑定:
   
   
  1. new Binding(someQueue, someDirectExchange, "foo.bar")

Queue和TopicExchange之间通过通配路由键进行绑定:
   
   
  1. new Binding(someQueue, someTopicExchange, "foo.*")

Queue和FanoutExchange之间的绑定不需要路由键:
   
   
  1. new Binding(someQueue, someFanoutExchange)
我们同样提供了 BindingBuilder  使用流式API风格来简化绑定:
   
   
  1. Binding b = BindingBuilder.bind(someQueue).to(someTopicExchange).with("foo.*");
Binding实例自身仅仅持有关于连接的数据。换句话说,它不是一个活跃的组件。然而你在后面将会看到,Binding实例被AmqpAdmin类用来出发消息代理的行为。你同样可以看到Binding实例可以通过注解在@Configuration的类中使用@Bean进行定义。

还存在一些基础的类,这些类进一步简化了AMQP 相关的Queue,Exchange,Binding的创建。AmqpTemplate这个类同样在核心包中定义,它将在后面章节中讨论。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值