RabbitMQ使用简述

RabbitMQ基于AMQP协议。

AMQP:是一个高级抽象层消息通信协议,RabbitMQ是AMQP协议的实现

RabbitMQ使用:Exchange(交换机)根据routing-key(路由选择键)匹配相应的queue(队列)

 

Exchange有4中类型:

direct:exchange在和queue进行binding时会设置routingkey,进行消息发送时,只有设置相同的routingkey,交换机才会路由到相应的队列。

topic:和direct差不多,只是topic允许routingkey使用通配符'*','#'.来匹配到相应的queue

fanout:直接将消息路由到所有绑定的队列中

header:和以上三个都不一样,其路由的规则是根据header来判断,其中的header就是以下方法的arguments参数

参考:https://www.cnblogs.com/julyluo/p/6265775.html,https://www.jianshu.com/p/d5675b1c8112

Routing Key:Consumer在binding exchange和queue时指定;在Producer在发送消息时指定。
 
 
demo:
引入jar包:
<!-- RabbitMQ -->
    <dependency>
      <groupId>com.rabbitmq</groupId>
      <artifactId>amqp-client</artifactId>
      <version>5.0.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.amqp</groupId>
      <artifactId>spring-rabbit</artifactId>
      <version>2.0.0.RELEASE</version>
    </dependency>

增加RabbitMQ配置

<!-- rabbitMQ配置 -->
    <bean id="rabbitConnectionFactory"
          class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
        <constructor-arg value="172.16.1.15"/>
        <property name="username" value="admin"/>
        <property name="password" value="admin"/>
        <property name="channelCacheSize" value="8"/>
        <property name="port" value="5672"></property>
    </bean>
    <rabbit:admin connection-factory="rabbitConnectionFactory"/>

    <!--邮件相关队列-->
    <rabbit:queue name="test_email_queue" durable="true"/>
    <!--短信相关队列-->
    <rabbit:queue name="test_sms_queue" durable="true"/>

    <!--将队列和交换器通过路由键绑定-->
    <rabbit:direct-exchange name="TEST_MQ"
                            xmlns="http://www.springframework.org/schema/rabbit"
                            durable="true">
        <rabbit:bindings>
            <rabbit:binding queue="test_email_queue" key="email" ></rabbit:binding>
            <rabbit:binding queue="test_sms_queue" key="sms" ></rabbit:binding>
        </rabbit:bindings>
    </rabbit:direct-exchange>

    <!-- 创建rabbitTemplate 消息模板类 -->
    <bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate">
        <constructor-arg ref="rabbitConnectionFactory"></constructor-arg>
    </bean>

    <rabbit:listener-container connection-factory="rabbitConnectionFactory">
        <rabbit:listener queues="test_email_queue" ref="processUserEmail"
                         method="onMessage"/>
        <rabbit:listener queues="test_sms_queue" ref="processUserSms"
                         method="onMessage"/>
    </rabbit:listener-container>

实现类:(生产者写入MQ)

package com.study.demo.service.impl;

import com.study.demo.service.IUserReg;
import com.study.demo.service.busi.SaveUser;
import com.study.demo.vo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;


/**
 * 
 * @Description: RabbitMQ实现的异步用户注册
 * @author leeSmall
 * @date 2018年9月18日
 *
 */
@Service
@Qualifier("async")
public class AsyncProcess implements IUserReg{

    private Logger logger = LoggerFactory.getLogger(AsyncProcess.class);

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private SaveUser saveUser;


    public boolean userRegister(User user) {
        try {
            saveUser.saveUser(user);
            rabbitTemplate.send("TEST_MQ","email",
                    new Message(user.getEmail().getBytes(),new MessageProperties()));
            rabbitTemplate.send("TEST_MQ","sms",
                    new Message(user.getEmail().getBytes(),new MessageProperties()));
        } catch (AmqpException e) {
            logger.error(e.toString());
            return  false;
        }

        return true;
    }
}

消费者(监听调用该方法)

package com.study.demo.service.mq;

import com.study.demo.service.busi.SendEmail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 
 * @Description: RabbitMQ消息消费端监听邮件消息类
 * @author leeSmall
 * @date 2018年9月18日
 *
 */
@Component
public class ProcessUserEmail implements MessageListener {

    private Logger logger = LoggerFactory.getLogger(ProcessUserEmail.class);

    @Autowired
    private SendEmail sendEmail;

    public void onMessage(Message message) {
        logger.info("accept message,ready process......");
        sendEmail.sendEmail(new String(message.getBody()));

    }
}

 

package com.study.demo.service.mq;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.study.demo.service.busi.SendSms;

/**
 * 
 * @Description: RabbitMQ消息消费端监听sms消息类
 * @author leeSmall
 * @date 2018年9月18日
 *
 */
@Component
public class ProcessUserSms implements MessageListener {

    private Logger logger = LoggerFactory.getLogger(ProcessUserSms.class);

    @Autowired
    private SendSms sendSms;

    public void onMessage(Message message) {
        logger.info("accept message,ready process......");
        sendSms.sendSms(new String(message.getBody()));

    }
}

 

使用目的:解耦,加快上文响应时间

使用场景:下单时关于库存的扣减、邮件、短信、消息的推送等需要异步处理的地方

如何使用的:
库存的扣减:
用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。如下图:
 
传统模式的缺点:假如库存系统无法访问,则订单减库存将失败,从而导致订单失败,订单系统与库存系统耦合
应用消息队列后的方案:
 
订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功
库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作
假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦
 
 
 
邮件、短信的发送:
串行方式:

 
并行方式(异步):
消息队列方式(解耦):
posted @ 2018-10-18 13:40  乌瑟尔  阅读(336)  评论(0编辑  收藏  举报