spring 整合 rabbitmq

一、基本配置

1、pom添加以下jar

<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.amqp/spring-rabbit -->
<dependency>
   <groupId>org.springframework.amqp</groupId>
   <artifactId>spring-rabbit</artifactId>
   <version>2.1.7.RELEASE</version>
</dependency>

2、spring配置文件springContext.xml添加以下配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:task="http://www.springframework.org/schema/task" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    
           http://www.springframework.org/schema/context    
           http://www.springframework.org/schema/context/spring-context-3.0.xsd  
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
           http://www.springframework.org/schema/aop    
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd    
           http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
           ">
      

    <!-- 激活spring的注解. -->
    <context:annotation-config />
    <context:component-scan base-package="com.pinghengxing..*">
    </context:component-scan>
    <!-- rabbitmq producer配置 -->
   <import resource="classpath*:com/config/rabbitmq_producer.xml" />
   
       <!-- rabbitmq consumer配置 -->
   <import resource="classpath*:com/config/rabbitmq_consumer.xml" />
    
</beans>

3、rabbitmq_producer.xml生产者配置如下(其中配置了exchange的三种类型:fanout,direct,topic)


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:rabbit="http://www.springframework.org/schema/rabbit"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd
            http://www.springframework.org/schema/rabbit
            http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
    
    
    <!-- 引入rabbitmq配置文件 -->
    <context:property-placeholder  location="classpath:/com/config/rabbitmq.properties" />
    
    <!--连接工厂 publisher-confirms,publisher-returns等参数,用于消息确认-->
    <rabbit:connection-factory id="rabbitConnectionFactory"
    host="140.143.xx.xx" username="ww" password="ww" port="5672"
    virtual-host="ww" channel-cache-size="25" cache-mode="CHANNEL"
    publisher-confirms="true" publisher-returns="true" connection-timeout="200" />
    
    <!--定义admin,producer中的exchange,queue会自动的利用该admin自动在mq中生成 -->
    <rabbit:admin id="rabbitAdmin" connection-factory="rabbitConnectionFactory"/>
    
    <bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
        <property name="backOffPolicy">
            <bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
                <property name="initialInterval" value="200" />
                <property name="maxInterval" value="30000" />
            </bean>
        </property>
        <property name="retryPolicy">
            <bean class="org.springframework.retry.policy.SimpleRetryPolicy">
                <property name="maxAttempts" value="5"/>
            </bean>
        </property>
    </bean>
    

    <!--定义rabbitmq模板,可以指定连接工厂、exchange、queue等 -->
    <rabbit:template id="amqpTemplate" connection-factory="rabbitConnectionFactory" retry-template="retryTemplate" 
     message-converter="jsonMessageConverter" confirm-callback="confirmCallback" return-callback="returnCallback" mandatory="true" 
    />
    
<!--     <rabbit:template id="amqpTemplate" connection-factory="rabbitConnectionFactory" retry-template="retryTemplate"  -->
<!--      message-converter="jsonMessageConverter" confirm-callback="confirmCallback" return-callback="returnCallback" mandatory="true"  -->
<!--      exchange="myTopicExchange" routing-key="error.1"/> -->
    
    
    <!--队列声明:durable:true、false true:在服务器重启时,能够存活 exclusive:是否私有队列,如果私有,其他通道不能访问当前队列 
    autodelete:当没有任何消费者使用时,自动删除该队列 ,当连接关闭后是否自动删除队列;-->
    <!--用于发布/订阅模式的队列-->
    <rabbit:queue name="myFanoutQueue" durable="true" exclusive="false" auto-delete="false"/>
    <rabbit:queue name="myFanoutQueue2" durable="true" exclusive="false" auto-delete="false"/>
    <!-- 用于路由模式的队列 -->
    <rabbit:queue name="myDirectQueue" durable="true" exclusive="false" auto-delete="false" />
    <!-- 用于主题模式的队列 -->
    <rabbit:queue name="myTopicQueue_error" durable="true" exclusive="false" auto-delete="false"/>
    <rabbit:queue name="myTopicQueue_warn" durable="true" exclusive="false" auto-delete="false"/>
    <!-- 定义交换机 发布/订阅模式 -->
    <rabbit:fanout-exchange name="myFanoutExchange" durable="true" auto-delete="false">
        <rabbit:bindings>
            <rabbit:binding queue="myFanoutQueue"></rabbit:binding>
            <rabbit:binding queue="myFanoutQueue2"></rabbit:binding>
        </rabbit:bindings>
    </rabbit:fanout-exchange>
    
    
    <!-- 定义交换机 路由模式(需要routing-key-->
    <rabbit:direct-exchange name="myDirectExchange" durable="true" auto-delete="false">
        <rabbit:bindings>
            <rabbit:binding queue="myDirectQueue" key="direct"></rabbit:binding>
        </rabbit:bindings>
    </rabbit:direct-exchange>
    <!--定义交换机 主题模式-->
    <rabbit:topic-exchange  name="myTopicExchange" durable="true" auto-delete="false">
        <rabbit:bindings>
            <rabbit:binding queue="myTopicQueue_error"  pattern="error.#"></rabbit:binding>
            <rabbit:binding queue="myTopicQueue_error" pattern="warn.#"></rabbit:binding>
            <rabbit:binding queue="myTopicQueue_warn" pattern="warn.*"></rabbit:binding>
        </rabbit:bindings>
    </rabbit:topic-exchange>
    
    <!--消息转换器,转成json格式-->
    <bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter"></bean>
    
    
    <!-- 也可以通过注解方式 -->
    <!--confirmCallback回调 -->
<!--     <bean id="confirmCallback" class="com.pinghengxing.callback.ConfirmCallBack"/> -->
    <!--returnCallback回调 -->
<!--     <bean id="returnCallback" class="com.pinghengxing.callback.ReturnCallBack"/> -->
        

    
    
</beans>

3、rabbitmq_consumer.xml消费者配置如下:(其中定义了三种exchange类型对应队列的消费者 ,)


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:rabbit="http://www.springframework.org/schema/rabbit"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd
            http://www.springframework.org/schema/rabbit
            http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
    
    
    <!-- 引入rabbitmq配置文件 -->
    <context:property-placeholder  location="classpath:/com/config/rabbitmq.properties" />
    
    <!--连接工厂 publisher-confirms,publisher-returns等参数,用于消息确认-->
    <rabbit:connection-factory id="rabbitConnectionFactory"
    host="140.143.xx.xx" username="ww" password="ww" port="5672"
    virtual-host="ww" channel-cache-size="25" cache-mode="CHANNEL"
     connection-timeout="200" />

    
    <!--定义监听-->
    <!-- concurrency设置的是对每个listener在初始化的时候设置的并发消费者的个数, prefetch是每次从一次性从broker里面取的待消费的消息的个数 
        每个消费者对应的listener有个Exclusive参数,默认为false, 如果设置为true,concurrency就必须设置为1, 即只能单个消费者消费队列里的消息,
        适用于必须严格执行消息队列的消费顺序(先进先出)。 -->
    <rabbit:listener-container connection-factory="rabbitConnectionFactory" acknowledge="manual"
    prefetch="1" concurrency="1"  >
        <!-- 发布订阅模式监听 -->
        <rabbit:listener ref="fanOutReceiver" queue-names="myFanoutQueue" />
        <rabbit:listener ref="fanOutReceiver2" queue-names="myFanoutQueue2" />
        
        <!-- 路由模式监听 -->
        <rabbit:listener ref="directReceiver" queue-names="myDirectQueue"  />
        <rabbit:listener ref="directReceiver2" queue-names="myDirectQueue"  />
        <!-- 主题模式监听 -->
        <rabbit:listener ref="topicErrorReceiver" queue-names="myTopicQueue_error"/>
        <rabbit:listener ref="topicWarnReceiver" queue-names="myTopicQueue_warn"/>
    </rabbit:listener-container>
    
    <!--消费者实现类,也可以使用注解方式 -->
<!--     <bean id="directReceiver" class="com.pinghengxing.direct.DirectReceiver"/> -->
<!--     <bean id="fanOutReceiver" class="com.pinghengxing.fanout.FanOutReceiver"/> -->
<!--     <bean id="fanOutReceiver2" class="com.pinghengxing.fanout.FanOutReceiver2"/> -->
<!--     <bean id="topicErrorReceiver" class="com.pinghengxing.topic.TopicErrorReceiver"/> -->
<!--     <bean id="topicWarnReceiver" class="com.pinghengxing.topic.TopicWarnReceiver"/> -->

</beans>

二、编写测试代码(在此只进行Direct类型 交换机测试代码的表写,其他类型仿照此示例即可)

1、定义消息生产者(DirectProducer)


package com.pinghengxing.direct;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** 
 * @author ww
 */

public class DirectProducer {
    
    
    private static ApplicationContext ac;

    public static void sendMessage(String exchange,String routingKey,Object message){
        ac = new ClassPathXmlApplicationContext("classpath:com/config/springContext.xml");
        RabbitTemplate rt = ac.getBean(RabbitTemplate.class);
        
        for(int i=0;i<10;i++){
            rt.convertAndSend(exchange, routingKey, message+""+i);
        }
    }
     
    public static void main(String[] args) {
        DirectProducer.sendMessage("myDirectExchange","direct","路由模式");
    }

    
    
}  

2、定义消息消费者(DirectReceiver1,DirectReceiver1 )-多个消费者

消费者1

package com.pinghengxing.direct;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.stereotype.Component;

import com.rabbitmq.client.Channel;
@Component("directReceiver")
public class DirectReceiver implements ChannelAwareMessageListener{
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        System.out.println("************************direct111********************************");
        System.out.println("路由模式direct111 接收信息:"+new String(message.getBody()));
        System.out.println("********************************************************");
        //设置手工应答
//        if(true){
//            throw new Exception();
//        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                    
    }

    
}

消费者2


package com.pinghengxing.direct;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.stereotype.Component;

import com.rabbitmq.client.Channel;
@Component("directReceiver2")
public class DirectReceiver2 implements ChannelAwareMessageListener{
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        System.out.println("************************direct222********************************");
        System.out.println("路由模式direct222 接收信息:"+new String(message.getBody()));
        System.out.println("********************************************************");
        //设置手工应答
//        if(true){
//            throw new Exception();
//        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                    
    }

    
}

三、测试

1、进行测试,结果如下:(两个消费者都可以从队列中取到数据,且数据不重复)

四、confirm-callback监听(用于监听exchange是否接收成功)

1、在配置工厂连接的时候,设置publisher-confirms="true"

<rabbit:connection-factory id="rabbitConnectionFactory"
host="140.143.xx.xx" username="ww" password="ww" port="5672"
virtual-host="ww" channel-cache-size="25" cache-mode="CHANNEL"
publisher-confirms="true" publisher-returns="true" connection-timeout="200" />

2、在定义rabbitmq模板时,指定confirm-callback的实现类

<rabbit:template id="amqpTemplate" connection-factory="rabbitConnectionFactory" retry-template="retryTemplate"
message-converter="jsonMessageConverter" confirm-callback="confirmCallback" return-callback="returnCallback" mandatory="true"
/>

3、创建实现类ConfirmCallback,实现RabbitTemplate.ConfirmCallback接口


package com.pinghengxing.callback;

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

/**
 * confirm-callback监听(用于监听exchange是否接收成功)
 * @author ww
 *
 */
@Component("confirmCallback")
public class ConfirmCallBack implements  RabbitTemplate.ConfirmCallback{

    /**
    * CorrelationData 是在发送消息时传入回调方法的参数,可以用于区分消息对象。 CorrelationData对象中只有一个属性 String id。
    * 通过这个参数,我们可以区分当前是发送哪一条消息时的回调,并通过ack参数来进行失败重发功能
    * @param correlationData 回调的相关数据.
    * @param ack true for ack, false for nack
    * @param cause 专门给NACK准备的一个可选的原因,其他情况为null。
    */
    public void confirm(CorrelationData correlationData, boolean ack,String cause) {
        System.out.println("********************************************************");
        System.out.println("exChange确认" + ack + "   " + cause);
        System.out.println("********************************************************");
    }
    
}

4、测试

五、returnCallback监听(basicpublish推送消息到queue失败时回调)

1、在配置工厂连接的时候,设置publisher-returns="true"

<rabbit:connection-factory id="rabbitConnectionFactory"
host="140.143.xx.xx" username="ww" password="ww" port="5672"
virtual-host="ww" channel-cache-size="25" cache-mode="CHANNEL"
publisher-confirms="true" publisher-returns="true" connection-timeout="200" />

2、在定义rabbitmq模板时,指定return-callback的实现类,并且设置mandatory="true"

<rabbit:template id="amqpTemplate" connection-factory="rabbitConnectionFactory" retry-template="retryTemplate" 
 message-converter="jsonMessageConverter" confirm-callback="confirmCallback" return-callback="returnCallback" mandatory="true" 
/>

3、创建实现类ReturnCallBack,实现RabbitTemplate.ReturnCallback接口


package com.pinghengxing.callback;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

/**
 * 推送消息到queue失败时回调
 * @author ww
 *
 */
@Component("returnCallback")
public class ReturnCallBack implements RabbitTemplate.ReturnCallback {
    
    
        @Override
        public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
            System.out.println("********************************************************");
            System.out.println("失败确认:"+message+" | "+replyCode+" | "+replyText+" | "+exchange+" | "+routingKey);
            System.out.println("********************************************************");
        }


}

4、测试(更改routing_key的值为direct123,由于找不到对应的队列,报以下错误)

六、json转换(可以将map等自动转换成json格式)

1、pom.xml添加以下maven依赖

<dependency>
 <groupId>com.fasterxml.jackson.core</groupId>
 <artifactId>jackson-databind</artifactId>
 <version>2.7.5</version>
</dependency>

2、定义消息转换器,转成json格式

<bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter"></bean>

3、在定义rabbitmq模板时,指定转换器message-converter="jsonMessageConverter"

<rabbit:template id="amqpTemplate" connection-factory="rabbitConnectionFactory" retry-template="retryTemplate" 
 message-converter="jsonMessageConverter" confirm-callback="confirmCallback" return-callback="returnCallback" mandatory="true" 
/>

4、测试,创建map,进行生产,消费者接收到的信息如下:为json格式






原文地址:https://www.cnblogs.com/pinghengxing/p/11210295.html



posted @ 2022-08-21 14:37  z-laoyao  阅读(203)  评论(0编辑  收藏  举报