SpringMvc整合rabbitMQ

0.我的目录结构

1.需要依赖的jar包 

<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>3.5.7</version>
</dependency>

<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-amqp</artifactId>
    <version>1.5.6.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>4.2.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit</artifactId>
    <version>1.5.6.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.1.2.RELEASE</version>
</dependency>

2.生产者配置文件 applicationContext-rabbitmq-send.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:rabbit="http://www.springframework.org/schema/rabbit"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="
	http://www.springframework.org/schema/rabbit
	http://www.springframework.org/schema/rabbit/spring-rabbit-1.4.xsd
    http://www.springframework.org/schema/task  
    http://www.springframework.org/schema/task/spring-task-4.1.xsd
    http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
	<!--导入配置文件 -->
	<bean id="mysqlSource"
		  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:jdbcConfig.properties"/>
	</bean>
	
	<!-- 定义RabbitMQ的连接工厂 -->
	<rabbit:connection-factory id="connectionFactory"
							   username="${rabbit.username}" password="${rabbit.password}" host="${rabbit.host}" port="${rabbit.port}"
							   virtual-host="${rabbit.virtual-host}"
							   publisher-confirms="true"
							   publisher-returns="true"
							   channel-cache-size="5"
							   />

	<!-- 定义Rabbit模板,指定连接工厂以及定义exchange
		rabbitTemplate   
	 -->
	<!--定义rabbit template用于数据的接收和发送 -->
	<rabbit:template id="rabbitTemplate"  connection-factory="connectionFactory"
					 exchange="${rabbit.direct-exchange}" confirm-callback="CallBackMQ"
					 mandatory="true"
					 return-callback="ReturnCall"/>

	<!-- MQ的管理,包括队列、交换器等 -->
	<rabbit:admin connection-factory="connectionFactory" />
	
	<!--<rabbit:fanout-exchange name=""></rabbit:fanout-exchange>-->


	<!--定义queue -->
	<rabbit:queue name="queueZhoa111" auto-declare="true"/>

    <!-- 定义direct exchange,绑定queue -->
	<rabbit:direct-exchange name="exchangeZhoa111" auto-declare="true" durable="true">
		<rabbit:bindings>
			<rabbit:binding queue="queueZhoa111" key="zhoa"/>
		</rabbit:bindings>
	</rabbit:direct-exchange>

	<!--消息是否成功发送到Exchange 的回调-->
	<bean id="CallBackMQ" class="com.util.rabbitmq.CallBackMQ"></bean>
	<!--消息从Exchange路由到队列的回调,注意这里只有路由失败的时候才会调此方法-->
	<bean id="ReturnCall" class="com.util.rabbitmq.ReturnCall"></bean>
</beans>

3.消费者配置文件 applicationContext-rabbitmq-receive.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:rabbit="http://www.springframework.org/schema/rabbit"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="
	http://www.springframework.org/schema/rabbit
	http://www.springframework.org/schema/rabbit/spring-rabbit-1.4.xsd
    http://www.springframework.org/schema/task  
    http://www.springframework.org/schema/task/spring-task-4.1.xsd
    http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">

	<!--导入配置文件 -->
	<bean id="mysqlSource"
		  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:jdbcConfig.properties"/>
	</bean>
	
	<!-- 定义RabbitMQ的连接工厂 -->
	<rabbit:connection-factory id="connectionFactory"
							   username="${rabbit.username}" password="${rabbit.password}" host="${rabbit.host}" port="${rabbit.port}"
							   virtual-host="${rabbit.virtual-host}"
							   publisher-confirms="true"
							   publisher-returns="true"
							   channel-cache-size="5"
							   />

	<!-- MQ的管理,包括队列、交换器等 -->
	<rabbit:admin connection-factory="connectionFactory" />

	<!--定义消息队列queue -->
	<rabbit:queue name="queueZhoa111" auto-declare="true"/>

    <!-- 定义交换机,并且完成队列和交换机的绑定 -->
	<rabbit:direct-exchange name="exchangeZhoa111" auto-declare="true">
		<rabbit:bindings>
			<rabbit:binding queue="queueZhoa111" key="zhoa"/>
		</rabbit:bindings>
	</rabbit:direct-exchange>

	<!-- 定义监听 -->
	<!--定义消费者监听队列 acknowledge设置消费者手动确认消息 原因是:rabbitmq默认是自动确认消息的,不管消费者有没有消费成功
    只要消费者收到消息后就直接确认了,确认后rabbitmq就会将队列中的消息删除掉 如果消费者收到消息后实际没有消费成功,就会导致消息丢失
        -->
	<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual">
		<!-- 监听一个队列,当队列中有消息,就会自动触发类.方法,传递消息就作为方法的参数,根据方法声明的参数强转 -->
		<rabbit:listener ref="messageReceiver2"  queue-names="queueZhoa111"/>
	</rabbit:listener-container>

	<bean id="messageReceiver2" class="com.util.rabbitmq.CatHandler2"/>
</beans>

4.引入的配置文件配置 jdbcConfig.properties  (路径错误的话自己修改)

rabbit.host=127.0.0.1
rabbit.port=5672
rabbit.username=zsq
rabbit.password=zsq
rabbit.virtual-host=/zhang
rabbit.direct-exchange=exchangeZhoa

5. applicationContext.xml 引入配置文件 ,添加线程池配置

<!--添加配置文件-->
	<import resource="classpath*:applicationContext-rabbitmq-receive.xml" />
	<import resource="classpath*:applicationContext-rabbitmq-send.xml" />

	<!--添加线程池-->
	<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
		<!-- 核心线程数 -->
		<property name="corePoolSize" value="10" />
		<!-- 最大线程数 -->
		<property name="maxPoolSize" value="20" />
		<!-- 队列最大长度 -->
		<property name="queueCapacity" value="1800" />
		<!-- 线程池维护线程所允许的空闲时间,默认为60s -->
		<property name="keepAliveSeconds" value="60" />
	</bean>
	<!-- 注解式 -->
	<task:annotation-driven />

6.springmvcConfig.xml 配置文件,添加扫包范围

<context:component-scan base-package="com.util.rabbitmq"/>

7,核心代码 

 controller控制层,调用发送消息工具类

@RestController
@RequestMapping("/test")
public class RabbitMQTest {

    @Autowired
    private RabbitAckServiceImpl rabbitAckService;

    @RequestMapping("/test2")
    public void sendMessage2() {
        for (int i = 1; i <=100 ; i++) {
            Map<String,Object> map=new HashMap<>();
            map.put("hh","zsq"+i);
            System.out.println("to send message:  "+ map);
            String json = JSON.toJSONString(map);
            boolean zhoa = rabbitAckService.sendMessage("exchangeZhoa111","zhoa", json);
            if(zhoa){
                System.out.println("发送成功1");
            }else {
                System.out.println("发送失败");
            }
        }
    }
}

工具类发送消息 

@Service
public class RabbitAckServiceImpl {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * @param exchange      交换机
     * @param routingKey    路由key
     * @param message       消息
     */
    public boolean sendMessage(String exchange,String routingKey , String message) {
        boolean result=false;
        if(!checkParam(exchange,routingKey,message)){
            return false;
        }
        try {
            rabbitTemplate.convertAndSend(exchange,routingKey,message);
            result = true;
        }catch (AmqpException e){
            e.printStackTrace();
        }
        return result;
    }

    public boolean checkParam(String param1){
        if(StringUtils.isEmpty(param1)){
            return false;
        }else {
            return true;
        }
    }

    public boolean checkParam(String param1,String param2){
        if(StringUtils.isEmpty(param1)||StringUtils.isEmpty(param2)){
            return false;
        }else {
            return true;
        }
    }

    public boolean checkParam(String param1,String param2,String param3){
        if(StringUtils.isEmpty(param1)||StringUtils.isEmpty(param2)||StringUtils.isEmpty(param3)){
            return false;
        }else {
            return true;
        }
    }
}

 实现接口 , 消息发送到exchang交换机 ,  返回投递结果

public class CallBackMQ implements RabbitTemplate.ConfirmCallback {

    int i=1;
    @Override   //消息投递到exchange是否成功
    public void confirm(CorrelationData correlationData, boolean b, String s) {
        if (b) {
            //设置消息投递成功
            System.out.println("消息投递成功"+i);
            i++;
        } else {
            //消息投递失败
            System.out.println(s);
            System.out.println("消息投递失败");
        }
    }
}

 实现接口, 消息从Exchange交换机 发送到 对列Queue 失败时回调执行此方法

public class ReturnCall implements RabbitTemplate.ReturnCallback {
    /**
     *只有消息从Exchange路由到Queue失败才会回调这个方法
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        System.out.println("消息从Exchage路由到Queue失败");
    }
}

消费者消费 ,采用多线程异步消费 

//消费者 采用异步多线程消费
public class CatHandler2 implements ChannelAwareMessageListener {
    
    @Autowired
    private TaskExecutor taskExecutor;

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        taskExecutor.execute(new Consume(message,channel));
    }
}

 线程类方法

public class Consume implements  Runnable{

    private Message message;
    private Channel channel;

    public  Consume(Message message, Channel channel){
        this.message=message;
        this.channel=channel;
    }


    @Override
    public void run() {
        boolean falg = false;
        try {
            // msg就是rabbitmq传来的消息,需要的同学自己打印看一眼
            // 使用jackson解析
            Map map = JSON.parseObject(message.getBody(), Map.class);
            System.out.println(Thread.currentThread().getName()+"收到消息:我是可爱的小猪,我的名字是" + map.get("hh"));
            //Thread.sleep(2000);
            falg = true;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            MessageProperties properties = message.getMessageProperties();
            long tag = properties.getDeliveryTag();
            //消费成功后将手动确认消息
            if (falg) {
                //消息确认,发送成功
                try {
                    channel.basicAck(tag, false);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                //如果发送失败,消息会重新进入队列,再次被这个消费者消费
                //消息发送失败后,也可以将消息发送到别的队列,让其他消费者进行消费
                //第三个参数 true为重新将消息放入队列,如果设置为false,则抛弃这条消息
                try {
                    channel.basicNack(tag, false, true);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

8.测试结果

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值