默认端口:5672,,5671
消息中间件:解耦,异步
AMQS:对消息协议的规定,类似http
概念:
Broker: 接收和分发消息的应用,我们在介绍消息中间件的时候所说的消息系统就是Message Broker。
Virtual host: 出于多租户和安全因素设计的,把AMQP的基本组件划分到一个虚拟的分组中,类似于网络中 的namespace概念。当多个不同的用户使用同一个RabbitMQ server提供的服务时,可以划分出多个vhost, 每个用户在自己的vhost创建exchange/queue等。 类似命名空间
Connection: publisher/consumer和broker之间的TCP连接。断开连接的操作只会在client端进行,Broker 不会断开连接,除非出现网络故障或broker服务出现问题。
Channel: 如果每一次访问RabbitMQ都建立一个Connection,在消息量大的时候建立TCP Connection的开 销将是巨大的,效率也较低。Channel是在connection内部建立的逻辑连接,如果应用程序支持多线程,通 常每个thread创建单独的channel进行通讯,AMQP method包含了channel id帮助客户端和message broker 识别channel,所以channel之间是完全隔离的。Channel作为轻量级的Connection极大减少了操作系统建立 TCP connection的开销。 channel是根据TCP连接开辟出来的
Exchange(交换机): message到达broker的第一站,根据分发规则,匹配查询表中的routing key,分发消息到queue 中去。常用的类型有:direct (point-to-point), topic (publish-subscribe) and fanout (multicast)。
Queue: 消息最终被送到这里等待consumer取走。一个message可以被同时拷贝到多个queue中。
Binding: exchange和queue之间的虚拟连接,binding中可以包含routing key。Binding信息被保存到 exchange中的查询表中,用于message的分发依据。
注意生产者和消费者位置
消息默认存在内存中,如果down机消息会消失------------->有办法
1.RabbitMQ服务端安装:先安装erlang环境,再安装rabbitMQ服务端
安装成功
打开控制台
打开浏览器 http://127.0.0.1:15672
打开控制台之后可以添加用户,设置访问权限
public static void main(String[] argv) throws Exception {
Connection connection=ConnectionUtil.getConnection();
Channel channel = connection.createChannel();
//队列允许持久化,队列可以其他channel调用,没有任何消费者消费时自动删除队列,队列配置(消息寿命,容纳消息数量等信息)
channel.queueDeclare(ConnectionUtil.QUEUE_NAME, true, false, false, null);
String message = "Hello World!";
//默认路由,队列名,消息配置先为null
channel.basicPublish("", ConnectionUtil.QUEUE_NAME, null, message.getBytes());
channel.close();
System.out.println(" Sent '" + message + "'");
}
public class Consumer {
public static void main(String[] args) throws Exception{
getMessage();
}
public static void getMessage()throws Exception{
Connection connection= ConnectionUtil.getConnection();
Channel channel = connection.createChannel();
//channel.queueDeclare(ConnectionUtil.QUEUE_NAME, false, false, false, null);
//消费消息
DefaultConsumer deliverCallback = new DefaultConsumer(channel) {
//envelope,可以拿消息标识路由 properties,消息配置 body消息
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body, "UTF-8"));
}
};
//开始消费
channel.basicConsume(ConnectionUtil.QUEUE_NAME, true, deliverCallback);
}
}
消费
metricsCollector:数据采集器
RabbitMQ通过一帧(Frame)一帧进行数据传输
channel--->connnection--->socket
发送确认代码:可以测试发送到错的交换机会报错
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
//rabbitTemplate.setMandatory(true);
//发送确认的回调,发送成功
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println(ack); //消息是否成功
System.out.println(cause); //失败原因
System.out.println(correlationData); //类似于业务id
}
});
return rabbitTemplate;
}
也可以设置多个callBack函数:
设置消息回调
//开启失败回调
rabbitTemplate.setMandatory(true);
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
//message : 发送的消息 "hello"+ 发送消息的配置(如过期时间等。。)
System.out.println(message);
//状态码
System.out.println(replyCode);
//失败信息
System.out.println(replyText);
System.out.println(exchange);
System.out.println(routingKey);
}
});
return rabbitTemplate;
消息序列化:JSON.toJSONString(map)
消费端:
有两种接收消息的方式有什么区别呢???会有乱码问题,springboot会查参数中是否包含text,如果是文本类型就会给转成String,否则直接返回body时byte数组========>1.设置消息类型为文本 见代码
第一种方式spring会按照参数的类型进行赋值。。
备用交换机:
队列设置时的配置参数
交换机配置参数
设置备用交换机:
@Bean
public DirectExchange defaultExchange() {
Map<String, Object> map = new HashMap<>();
//声明备用交换机,已经存在的
map.put("alternate-exchange","name");
//如果交换机directExchangeTest2失败,将会调用备用交换机name
return new DirectExchange("directExchangeTest2",false,false,map);
}