功能目标
1.Spring整合RabbitMq 实现 helloworld 工作模式
2.实现Work Queue 工作模式
3.实现Publish 工作模式
3.实现Routing 工作模式
4.实现Topic 工作模式
5.实现生产者Confirm & Return 确保消息发送成功
6.实现消费者 ACK,确保消费成功
7.实现延迟消息队列
整合流程
1.打开SpringAMQP 网站,这里有maven 引入,xml基本配置文件;SpringAMQP
2.新建项目引入jar包,复制相关xml配置文件
3.WorkerQueue 整合代码
3.1 生产者
<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">
<!-- 定义rabbitmq connectionFactory -->
<rabbit:connection-factory id="connectionFactory" host=""
port="5672" virtual-host="jtfu-firstmq" username="jtfu"
password="jtfu123" publisher-returns="true" confirm-type="CORRELATED"/>
<!--定义rabbitTemplate对象操作可以在代码中方便发送消息-->
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
<!--定义管理交换机、队列-->
<rabbit:admin connection-factory="connectionFactory"/>
<!-- 定义队列-->
<rabbit:queue id="spring_queue_helloWorld" name="spring_queue_helloWorld"/>
</beans>
public class ProducerApp {
public static void main(String[] args) throws InterruptedException {
ApplicationContext context =
new GenericXmlApplicationContext("classpath:/rabbit-context.xml");
AmqpTemplate template = context.getBean(AmqpTemplate.class);
for (int i=0;i<10;i++){
template.convertAndSend("spring_queue_helloWorld", "helloWorld");
}
}
}
3.2 消费者
<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">
<!-- 定义rabbitmq connectionFactory -->
<rabbit:connection-factory id="connectionFactory" host=""
port="5672" virtual-host="jtfu-firstmq" username="jtfu"
password="jtfu123" publisher-returns="true" confirm-type="CORRELATED"/>
<!--定义rabbitTemplate对象操作可以在代码中方便发送消息-->
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
<!--定义管理交换机、队列-->
<rabbit:admin connection-factory="connectionFactory"/>
<!-- Spring声明一个bean-->
<bean id="workerListener" class="com.jtfu.mq.study.listener.WorkerListener"></bean>
<!--声明一个队列-->
<rabbit:queue id="spring_queue_helloWorld" name="spring_queue_helloWorld"/>
<!--添加Listener,监听队列消息 acknowledge:手动签收消息,prefetch:每次拉取一条消息 -->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" prefetch="1">
<rabbit:listener ref="workerListener" queues="spring_queue_helloWorld"></rabbit:listener>
</rabbit:listener-container>
</beans>
public class WorkerListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
MessageProperties messageProperties = message.getMessageProperties();
System.out.println(new String(message.getBody()));
//手动签收消息
channel.basicAck(messageProperties.getDeliveryTag(),false);
}
@Override
public void onMessage(Message message) {
}
}
4.实现Publish 工作模式
交换机绑定多个队列,多个队列可以同时监听消息并消费;
生产者
<rabbit:fanout-exchange name="spring_fanout_exchange">
<rabbit:bindings>
<rabbit:binding queue="spring_queue_helloWorld"></rabbit:binding>
<rabbit:binding queue="spring_queue_publish"></rabbit:binding>
</rabbit:bindings>
</rabbit:fanout-exchange>
消费者
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" prefetch="1">
<rabbit:listener ref="workerListener" queues="spring_queue_helloWorld"></rabbit:listener>
<rabbit:listener ref="publishListener" queues="spring_queue_publish"></rabbit:listener>
</rabbit:listener-container>
5.实现Routing 工作模式
交换机绑定多个队列,并指定完整的routing key
生产者
<rabbit:direct-exchange name="spring-direct_exchange">
<rabbit:bindings>
<rabbit:binding queue="spring_queue_direct_kawasaki" key="kawasaki"></rabbit:binding>
<rabbit:binding queue="spring_queue_direct_honda" key="honda"></rabbit:binding>
</rabbit:bindings>
</rabbit:direct-exchange>
6.实现Topic 工作模式
<rabbit:topic-exchange name="spring_topic_exchange">
<rabbit:bindings>
<rabbit:binding pattern="moto.#" queue="spring_queue_direct_honda"></rabbit:binding>
<rabbit:binding pattern="moto.*" queue="spring_queue_direct_kawasaki"></rabbit:binding>
</rabbit:bindings>
</rabbit:topic-exchange>
7.实现生产者Confirm & Return 确保消息发送成功,实现消费者 ACK,确保消费成功
7.1 生产者确保消息发送成功;首先配置文件中开启发送确认模式 publisher-confirms=“true” publisher-returns="true"
<rabbit:connection-factory id="connectionFactory" host="8.140.112.183"
port="5672" virtual-host="jtfu-firstmq" username="jtfu"
password="jtfu123" publisher-confirms="true" publisher-returns="true"/>
blic class ProducerApp {
public static void main(String[] args) throws InterruptedException {
ApplicationContext context =
new GenericXmlApplicationContext("classpath:/rabbit-context.xml");
RabbitTemplate template = context.getBean(RabbitTemplate.class);
Map map=new HashMap();
map.put("moto.kawasaki","Z900");
map.put("moto.honda.Cbr650","CBR650");
map.put("moto.honda.Cbr650.ssss","CBR650");
map.put("honda.Cbr650.ssss","CBR650");
Set<Map.Entry> set = map.entrySet();
template.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String s) {
System.out.println("进入confirm。。。。。");
if(ack){
//消息进入交换机
System.out.println("消息进入交换机。。。。");
}else {
System.out.println("消息未找到交换机。。。。");
}
}
});
//设置交换机处理失败消息的模式 为true的时候,消息达到不了 队列时,会将消息重新返回给生产者
template.setMandatory(true);
template.setReturnCallback(new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
System.out.println("进入returns。。。未找到相应routing,");
}
});
for (Map.Entry entry : set) {
template.convertAndSend("spring-direct_exchange","====sss",entry.getValue().toString().getBytes(StandardCharsets.UTF_8));
}
}
8.实现延迟消息队列 ,RabbitMq 不支持延迟队列,需要使用TTL 与 死信队列配合达到延迟队列的目的;
8.1 消息在以下情况会进入死信状态
1. 消息到达ttl设置的时间未被消费掉
2. 消息队列达到最大值,新来的消息成为死信
3. 消息发送给消费端后,消费端拒绝签收并丢弃的消息;
目的:实现10秒钟的延迟队列;
1.创建普通交换机 与 普通队列;
2.创建死信交换机 与 死信队列
3.配置普通队列参数,设置超时时间,死信队列名称,发送给死信队列的routing key
<rabbit:queue id="orderQueue" name="orderQueue">
<rabbit:queue-arguments>
<!-- 设置队列的过期时间,相关参数可以从rabbitMqServer获取-->
<entry key="x-message-ttl" value="10000" value-type="java.lang.Integer" ></entry>
<!-- 设置队列的最大容量-->
<entry key="x-max-length" value="10" value-type="java.lang.Integer" ></entry>
<!-- 死信队列交换机名-->
<entry key="x-dead-letter-exchange" value="order_exchange_dead"></entry>
<!-- 发送给死信交换机的routing key-->
<entry key="x-dead-letter-routing-key" value="dlx.order"></entry>
</rabbit:queue-arguments>
</rabbit:queue>
<rabbit:direct-exchange name="order_exchange">
<rabbit:bindings>
<rabbit:binding queue="orderQueue" key="order"></rabbit:binding>
</rabbit:bindings>
</rabbit:direct-exchange>
消费者监听死信队列,达到延迟的目的
<rabbit:listener ref="orderDeadListener" queues="orderQueueDead"></rabbit:listener>