1.RabbitMQ支持的消息模型
通过访问官方网站,我们可以看到rabbitmq支持如下的消息模型
这里我们要注意一下:每个版本的rabbitmq支持的消息模型不太一样,比如第7个消息模型是最新版Rabbitmq(也就是3.8.3)才开始支持的.
2.进入正题
今天我们来介绍一下第一种消息模型Hello World模型.
在上图的模型中,有以下概念:
- P:生产者:也就是要发送消息的程序
- C:消费者:消息的接受者,会一直等待消息到来.
- queue:消息队列,图中红色部分.类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从中取出消息.
开发生产者
package com.rabbitmq.helloworld;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.utils.RabbitMQUtils;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author zty
* @date 2020/4/9 下午4:51
* @description:
*/
public class Provider {
//生产消息
@Test
public void testSendMessage() throws IOException, TimeoutException {
//创建连接mq的连接工厂对象
ConnectionFactory connectionFactory = new ConnectionFactory();
//设置连接rabbitmq主机
connectionFactory.setHost("127.0.0.1");
//设置端口号
connectionFactory.setPort(5672);
//设置连接哪个虚拟主机
connectionFactory.setVirtualHost("/ems");
//设置访问虚拟主机的用户名和密码
connectionFactory.setUsername("ems");
connectionFactory.setPassword("123456");
//获取连接对象
Connection connection = connectionFactory.newConnection();
//Connection connection1 = RabbitMQUtils.getConnection();
//通过连接中的通道
Channel channel = connection.createChannel();
//通道绑定对应消息队列
//参数1:队列名称
//参数2:定义队列特性是否要持久化,true 持久化队列,false 不持久化,下次重启时就会被删除
//参数3:exclusive 是否独占队列,如果为false,则我们声明的队列可以被其他链接所使用
//参数4:autoDelete
//参数5:额外附加参数
channel.queueDeclare("hello",false,false,false,null);
//发布消息
//参数1:交换机名称 参数2:队列名称 参数3:传递消息的额外设置 参数4:消息的具体内容
channel.basicPublish("","hello",null,"hello rabbitmq".getBytes());
channel.close();
connection.close();
//调用工具类
//RabbitMQUtils.closeConnectionAndChanl(channel,connection);
}
}
开发消费者
package com.rabbitmq.helloworld;
import com.rabbitmq.client.*;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author zty
* @date 2020/4/9 下午5:53
* @description:
*/
public class Customer {
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/ems");
connectionFactory.setUsername("ems");
connectionFactory.setPassword("123456");
//创建连接对象
Connection connection = connectionFactory.newConnection();
//创建通道
Channel channel = connection.createChannel();
//通道绑定对象
channel.queueDeclare("hello",false,false,false,null);
//消费消息
//参数1:消费那个队列
//参数2:开始消息的自动
//参数3:消费时的回调接口
channel.basicConsume("hello",true,new DefaultConsumer(channel){
@Override//最后一个参数:消息队列中取出的消息
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("new String(body) = "+new String(body));
}
});
// channel.close();
// connection.close();
}
}
测试
- 发送两次消息
- 查看控制台
- 确实进了两条消息,然后我们测试一下消费者
- 这里要提醒一下:如果消费者代码中我们不关闭连接,那么消费者会一直监听,如果有生产者发送消息,那么消费者就会立即获得那条消息.
优化
稍微细心一点我们就会发现,这个代码有大量冗余,我们知道,重复的建立连接是很浪费资源的,而这里面的建立连接是相同的,所以我们写一个建立连接和释放连接的工具类来降低代码冗余
package com.rabbitmq.utils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author zty
* @date 2020/4/9 下午7:35
* @description:
*/
public class RabbitMQUtils {
private static ConnectionFactory connectionFactory;
static {
//重量级资源 类加载时只执行一次
connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/ems");
connectionFactory.setUsername("ems");
connectionFactory.setPassword("123456");
}
//定义提供连接对象的方法
public static Connection getConnection(){
try {
return connectionFactory.newConnection();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//关闭通道和关闭连接工具方法
public static void closeConnectionAndChanl(Channel channel,Connection coon){
try {
if(channel!=null){
channel.close();
}
if(coon!=null){
coon.close();
}
coon.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
我将建立连接写在静态代码块中,只需要在类加载时候执行一次,之后就无需再重复建立连接了.
自此我们就可以将上面代码中的建立连接和释放连接给简化了