Spring AMQP项目是用于开发AMQP的解决方案。 我们提供一个“模板”作为发送和接收消息的抽象。我们还为普通POJO进行提供消息处理支持。这些库促进AMQP资源的管理,同时支持使用依赖注入和声明式配置。 在所有情况下,您将看到与Spring Framework中的JMS支持的相似之处
依赖
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
兼容性
最小的Spring Framework 版本5.1.x
最低的amqp-client的java客户端库版本是5.4.0。
示例:
使用简单同步的Java发送和接收消息:
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
ConnectionFactory connectionFactory = new CachingConnectionFactory();
AmqpAdmin admin = new RabbitAdmin(connectionFactory);
admin.declareQueue(new Queue("myqueue"));
AmqpTemplate template = new RabbitTemplate(connectionFactory);
template.convertAndSend("myqueue", "foo");
String foo = (String) template.receiveAndConvert("myqueue");
使用spring xml配置文件声明
ApplicationContext context =
new GenericXmlApplicationContext("classpath:/rabbit-context.xml");
AmqpTemplate template = context.getBean(AmqpTemplate.class);
template.convertAndSend("myqueue", "foo");
String foo = (String) template.receiveAndConvert("myqueue");
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/rabbit
https://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<rabbit:connection-factory id="connectionFactory"/>
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
<rabbit:admin connection-factory="connectionFactory"/>
<rabbit:queue name="myqueue"/>
</beans>
By default, the <rabbit:admin/> declaration automatically looks for beans of type Queue, Exchange, and Binding and declares them to the broker on behalf of the user. As a result, you need not use that bean explicitly in the simple Java driver.
springboot 配置
ApplicationContext context =
new AnnotationConfigApplicationContext(RabbitConfiguration.class);
AmqpTemplate template = context.getBean(AmqpTemplate.class);
template.convertAndSend("myqueue", "foo");
String foo = (String) template.receiveAndConvert("myqueue");
........
@Configuration
public class RabbitConfiguration {
@Bean
public ConnectionFactory connectionFactory() { return new CachingConnectionFactory("localhost");
}
@Bean
public AmqpAdmin amqpAdmin() { return new RabbitAdmin(connectionFactory());
}
@Bean
public RabbitTemplate rabbitTemplate() { return new RabbitTemplate(connectionFactory());
}
@Bean
public Queue myQueue() { return new Queue("myqueue");
} }
使用springboot 自动配置 和pojo异步监听器
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public ApplicationRunner runner(AmqpTemplate template) {
return args -> template.convertAndSend("myqueue", "foo");
}
@Bean
public Queue myQueue() {
return new Queue("myqueue");
}
@RabbitListener(queues = "myqueue")
public void listen(String in) {
System.out.println(in);
}
}
Spring AMQP包含两个模块(每个模块在发行版中由一个JAR表示):Spring - AMQP和Spring -rabbit。“spring-amqp”模块包含org.springframework.amqp。核心包。在该包中,您可以找到表示核心AMQP“模型”的类。我们的目的是提供不依赖于任何特定AMQP代理实现或客户端库的通用抽象。最终用户代码可以更容易跨供应商实现移植,因为它只能针对抽象层开发。然后,这些抽象由特定于代理的模块实现,如“spring-rabbit”。目前只有一个RabbitMQ实现。然而,除了RabbitMQ之外,抽象还在. net中使用Apache Qpid进行了验证。由于AMQP在协议级别上运行,原则上,您可以将RabbitMQ客户机与支持相同协议版本的任何代理一起使用,但是我们目前不测试任何其他代理。
本文假设您已经熟悉AMQP规范的基础知识。如果没有,请查看其他参考资料中列出的资源
消息
0-9-1 AMQP规范没有定义消息类或接口。相反,在执行basicPublish()等操作时,内容作为字节数组参数传递,其他属性作为单独的参数传递。Spring AMQP将消息类定义为更通用的AMQP域模型表示的一部分。Message类的目的是将主体和属性封装在单个实例中,这样API就可以更简单。下面的示例显示消息类定义:
public class Message {
private final MessageProperties messageProperties;
private final byte[] body;
public Message(byte[] body, MessageProperties messageProperties) {
this.body = body;
this.messageProperties = messageProperties;
}
public byte[] getBody() {
return this.body;
}
public MessageProperties getMessageProperties() {
return this.messageProperties;
} }
MessageProperties接口定义了几个常见的属性,如'messageId'、'timestamp'、'contentType'等。您还可以通过调用setHeader(String key, Object value)方法,使用用户定义的“header”扩展这些属性。
从版本1.5.7、1.6.11、1.7.4和2.0.0开始,如果消息体是序列化的可序列化java对象,那么在执行toString()操作(例如日志消息)时,它将不再反序列化(默认情况下)。这是为了防止不安全的反序列化。默认情况下,只有java。util和java。lang类是反序列化的。要恢复到前面的行为,可以通过调用Message.addWhiteListPatterns(…)添加允许的类/包模式。支持简单的通配符,例如com.something。* .MyClass。不能反序列化的主体在日志消息中由byte[]表示。
交换机
Exchange接口表示AMQP交换机,这是消息生成器发送到的对象。代理虚拟主机中的每个Exchange都有一个惟一的名称和一些其他属性。下面的例子展示了Exchange接口:
public interface Exchange {
String getName();
String getExchangeType();
boolean isDurable();
boolean isAutoDelete();
Map<String, Object> getArguments();
}
如您所见,Exchange还有一个“类型”,由ExchangeTypes中定义的常量表示。基本类型有:direct、topic、fanout '和header。在核心包中,您可以找到每种类型的Exchange接口实现。就处理队列绑定的方式而言,这些交换类型之间的行为各不相同。例如,直接交换允许使用固定路由键(通常是队列的名称)绑定队列。主题交换支持使用路由模式绑定,其中可能分别包含用于“恰好为1”和“零或更多”的“*”和“#”通配符。Fanout exchange发布到绑定到它的所有队列,而不考虑任何路由键。有关这些类型和其他交换类型的更多信息,请参阅其他参考资料。
AMQP规范还要求任何代理提供没有名称的“缺省”直接交换。声明的所有队列都绑定到该缺省交换器,其名称作为路由键。您可以在AmqpTemplate中了解更多关于Spring AMQP中默认Exchange的用法。
队列
Queue类表示消息使用者从其中接收消息的组件。与各种Exchange类一样,我们的实现也是这个核心AMQP类型的抽象表示。下面的清单显示了Queue类:
public class Queue {
private final String name;
private volatile boolean durable;
private volatile boolean exclusive;
private volatile boolean autoDelete;
private volatile Map<String, Object> arguments;
/**
* The queue is durable, non-exclusive and non auto-delete.
*
* @param name the name of the queue.
*/
public Queue(String name) {
this(name, true, false, false);
}
// Getters and Setters omitted for brevity
}
注意,构造函数接受队列名称。根据实现的不同,管理模板可能提供生成惟一命名队列的方法。这样的队列可以用作“答复”地址,也可以用于其他临时情况。因此,自动生成队列的“exclusive”和“autoDelete”属性都将被设置为“true”。
有关使用名称空间支持(包括队列参数)声明队列的信息,请参阅配置代理中的队列一节
绑定
假定生产者向交换器发送消息,消费者从队列接收消息,那么将队列连接到交换器的绑定对于通过消息传递将生产者和消费者连接起来是至关重要的。在Spring AMQP中,我们定义了一个绑定类来表示这些连接。本节将回顾将队列绑定到交换器的基本选项。
您可以使用固定路由键将队列绑定到DirectExchange,如下面的示例所示:
new Binding(someQueue, someDirectExchange, "foo.bar");
您可以使用路由模式将队列绑定到TopicExchange,如下面的示例所示:
new Binding(someQueue, someTopicExchange, "foo.*");
您可以将队列绑定到没有路由键的FanoutExchange,如下面的示例所示:
new Binding(someQueue, someFanoutExchange);
我们还提供了一个BindingBuilder来简化“fluent API”风格,如下例所示:
Binding b = BindingBuilder.bind(someQueue).to(someTopicExchange).with("foo.*");
为了清晰起见,前面的示例显示了BindingBuilder类,但是当为“bind()”方法使用静态导入时,这种样式可以很好地工作。
绑定类的实例本身只包含关于连接的数据。换句话说,它不是一个“活动”组件。但是,正如稍后在配置代理时将看到的,AmqpAdmin类可以使用绑定实例来实际触发代理上的绑定操作。同样,正如您在同一节中看到的,您可以通过在@Configuration类中使用Spring的@Bean注释来定义绑定实例。还有一个方便的基类,它进一步简化了生成AMQP相关bean定义的方法,并识别队列、交换和绑定,以便在应用程序启动时在AMQP代理上声明它们。
AmqpTemplate也在核心包中定义。作为实际AMQP消息传递中涉及的主要组件之一,我们将在其自己的部分(参见AmqpTemplate)中详细讨论它。