# 消息机制

## 1.简介

融租易 的消息系统提供`唯一`和`广播`以及`主题`三种模式,实现方式为 RabbitMQ。

### 1.1 RabbitMQ介绍

RabbitMQ 是实现 AMQP(高级消息队列协议)的消息中间件的一种,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。消息中间件主要用于组件之间的解耦。rabbitmq多应用于批量数据异步处理、并行任务串行化,高负载任务的负载均衡等 重量级,高并发,异步高可靠性场景。

### 1.2 配置rabbit

(1)用户要先在 `applicationContext-rabbitmq.xml` 中 添加`<beans:import resource="rabbitmq.xml"/>`。

(2)然后在`config.properties`中自行添加mq相关的配置如图:

![](/assets/config.png)

## 2 自定义消息

在融租易的接口管理的消息队列模块定义功中,提供了自定义队列和交换机的功能,可以根据配置实现自定义的队列和交换机的匹配,避免了在xml中的繁琐配置。

### 2.1 定义交换机

在接口管理的消息队列定义模块中,首先进行交换机的定义,界面如图:![](/assets/exchange.png)注意:

交换机名称不可以重复定义,一个交换机可以对应多个队列。

交换机类型可以分为**direct\(唯一模式\),topic\(主题模式\),fanout\(广播模式\),**rabbitmq会根据你的交换机类型和定义的路由键,完成消息的转发**。**

持久化(durable):交换机在服务关闭后,清除与否。

自动删除(auto-delete):当交换机没有队列绑定时,删除与否。

### 2.2 定义队列和路由键

定义完交换机后,你还需要定义你的队列和相应的匹配模式(既路由键)界面如图:![](/assets/queue.png)注意:

队列名称不可以重复,但是一个队列可以对应多个交换机。

匹配模式(routing-key):此处的匹配模式即为路由键

持久化(durable):队列在服务关闭后,清除与否。

自动删除(auto-delete):当队列没有绑定交换机时,删除与否。

私有队列(exclusive):  仅创建者可以使用的私有队列,断开后自动删除.

## 3 发送消息/接收消息

在融租易中,消息的发送和接收都提供了可以直接调用的接口

### 3.1 消息的匹配规则

1.唯一模式\(**Direct Exchange**\):

处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “hls”,则只有被标记为“hls”的消息才被转发,不会转发hls.sys,也不会转发hls.fnd,只会转发hls。

2.广播模式\(**Fanout Exchange**\):

不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。

3.主题模式\(**Topic Exchange**\):

将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“\#”匹配一个或多个词,符号“\*”匹配不多不少一个词。因此“hls.\#”能够匹配到“hls.sys.adaptor”,但是“hls.\*” 只会匹配到“hls.sys”。

### 3.2 发送消息

融租易中,通过调用`IRabbitProducerService`接口中的`sendMessage(JSONObject json)`方法,来实现消息的发送

注意:

接口调用时必须使用spring中的注入方式。

json必须按照格式如:

```json
 {
    "header":{
        "orgCode":"hls",
        "apiName":"demoMQ",
        "sysCode":"fnd",
        "routingKey":"hls",
        "respCode":"sys",
        "respMsg":"recived",
        "transDate":"Thu Jul 27 2017 10:47:17 GMT+0800 (CST)",
        "transNo":"123"
    },
    "busiData":{
        "contractId":1
    },
    "securityInfo":{
        "userName":"hd001",
        "userPassword":"123456"
    }
}
```

### 3.3 接收消息

融租易中对消息的接收进行了统一处理,只需要单独编写业务的实现类即可(此处必须实现IRabbitMessageConsumerService接口),消息会先被内部的消息监听接口统一处理,然后再根据消息中的apiName找到对应的接口实现类,调用其中的process方法。

示例代码:

```java
@Service
public class ConsumerDemoServiceImpl implements IRabbitMessageConsumerService {

    @Autowired(required = false)
    private IRabbitProducerService iRabbitProducerService;//消息发送类
    @Autowired
    private IXXXService service;//业务类

    @Override
    public String getApiName() {
        return "demoMQ";
    }

    @Override
    public void process(JSONObject json) {
        //业务处理
        service.doSomething(json)
        //返回消息
        ResponseInfo responseInfo = null;
        try {
            responseInfo = RabbitMQUtils.getResposeInfo(json);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        JSONObject respose= new JSONObject().fromObject(responseInfo);

        iRabbitProducerService.sendMessage(respose);

    }
}
```

###