RabbitMq原理 请参考这篇文档和Springboot整合RabbitMq
1.Rabbit安装
1.安装Erlang
由于RabbitMQ依赖Erlang, 所以需要先安装Erlang。
从EPEL源安装(这种方式安装的Erlang版本可能不是最新的,有时候不能满足RabbitMQ需要的最低版本)
# 启动EPEL源
$ sudo yum install epel-release
# 安装erlang
$ sudo yum install erlang
2.完成后安装RabbitMQ
先下载rpm:
wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.6/rabbitmq-server-3.6.6-1.el7.noarch.rpm
下载完成后安装:
yum install rabbitmq-server-3.6.6-1.el7.noarch.rpm
3.关于RabbitMQ的一些基本操作
sudo chkconfig rabbitmq-server on # 添加开机启动RabbitMQ服务
sudo /sbin/service rabbitmq-server start # 启动服务
sudo /sbin/service rabbitmq-server status # 查看服务状态
sudo /sbin/service rabbitmq-server stop # 停止服务
sudo /sbin/service rabbitmq-server restart # 重启服务
# 查看当前所有用户
sudo rabbitmqctl list_users
# 查看默认guest用户的权限
sudo rabbitmqctl list_user_permissions guest
# 由于RabbitMQ默认的账号用户名和密码都是guest。
sudo rabbitmqctl delete_user guest
# 添加新用户
sudo rabbitmqctl add_user username password
# 设置用户tag
sudo rabbitmqctl set_user_tags username administrator
# 赋予用户默认vhost的全部操作权限
sudo rabbitmqctl set_permissions -p / username ".*" ".*" ".*"
# 查看用户的权限
sudo rabbitmqctl list_user_permissions username
4.开启web管理接口
如果只从命令行操作RabbitMQ,多少有点不方便。幸好RabbitMQ自带了web管理界面,只需要启动插件便可以使用。
sudo rabbitmq-plugins enable rabbitmq_management
然后通过浏览器访问
http://localhost:15672
输入用户名和密码访问web管理界面了。
4. 开启用户远程访问
默认情况下,RabbitMQ的默认的guest用户只允许本机访问, 如果想让guest用户能够远程访问的话,只需要将配置文件中的loopback_users列表置为空即可,/etc/rabbitmq/rabbitmq.config默认是没有,只需要创建即可,然后加入配置,.
一定不要忽略,然后执行重启命令
[
{rabbit, [
{loopback_users, []}
]
}
].
sudo /sbin/service rabbitmq-server restart
然后就可以远程连接上rabbitmq了
2. 常用模式
通用RabbitMq连接代码
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.6.5</version>
</dependency>
</dependencies>
public class ConnectionUtils {
private static String virtualHost = "/";
public static Connection newConnection() throws IOException, TimeoutException {
// 1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
// 2.虚拟服务器
connectionFactory.setVirtualHost(virtualHost);
// 3.连接用户名
connectionFactory.setUsername("guest");
// 4.连接密码
connectionFactory.setPassword("guest");
// 5.连接地址
connectionFactory.setHost("127.0.0.1");
// 6.连接端口
connectionFactory.setPort(5672);
Connection connection = connectionFactory.newConnection();
return connection;
}
}
1.Direct模式
生产者
public class DirectProducer {
private static String EXCHANGE = "direct";
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接
Connection connection = ConnectionUtils.newConnection();
// 2.创建通道
Channel channel = connection.createChannel();
//3.绑定的交换机 参数1交互机名称 参数2 exchange类型
channel.exchangeDeclare(EXCHANGE, "direct");
String msg = "Direct模式生产消息";
System.out.println("生产者生产消息:" + msg);
String routingKey = "info";
// 4.生产消息
channel.basicPublish(EXCHANGE,routingKey ,null, msg.getBytes());
}
}
消费者
public class DirectConsumer {
private static String QUEUE_DIRECT = "direct";
private static String EXCHANGE = "direct";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
System.out.println("Direct消费者");
//1.创建连接
Connection connection = ConnectionUtils.newConnection();
// 2.创建通道
final Channel channel = connection.createChannel();
// 3.声明队列
/**
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
* queue:这没什么好说的,队列名
*
* durable:是否持久化,那么问题来了,这是什么意思?持久化,指的是队列持久化到数据库中。在之前的博文中也说过,如果RabbitMQ服务挂了怎么办,队列丢失了自然是不希望发生的。持久化设置为true的话,即使服务崩溃也不会丢失队列
* exclusive:是否排外,what? 这又是什么呢。设置了排外为true的队列只可以在本次的连接中被访问,也就是说在当前连接创建多少个channel访问都没有关系,但是如果是一个新的连接来访问,对不起,不可以,下面是我尝试访问了一个排外的queue报的错。还有一个需要说一下的是,排外的queue在当前连接被断开的时候会自动消失(清除)无论是否设置了持久化
* autoDelete:这个就很简单了,是否自动删除。也就是说queue会清理自己。但是是在最后一个connection断开的时候
* 设置队列的其他一些参数
*/
channel.queueDeclare(QUEUE_DIRECT, false, false, false, null);
/**
* String queue, String exchange, String routingKey
*/
channel.queueBind(QUEUE_DIRECT, EXCHANGE, "info");
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msgString = new String(body, "UTF-8");
System.out.println("短信消费者获取消息:" + msgString);
}
};
// 4.设置应答模式,true的时候为自动应答,false为手动应答,需要处理
channel.basicConsume(QUEUE_DIRECT, true, defaultConsumer);
}
}
2.Fanout模式
生产者
public class Producer {
private static String EXCHANGE = "sms_email";
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接
Connection connection = ConnectionUtils.newConnection();
// 2.创建通道
Channel channel = connection.createChannel();
//3.绑定的交换机 参数1交互机名称 参数2 exchange类型
channel.exchangeDeclare(EXCHANGE, "fanout");
String msg = "测试生产消息";
try {
// channel.txSelect();
// 4.生产消息
channel.basicPublish(EXCHANGE, "", null, msg.getBytes());
// int i = 1 / 0;
System.out.println("生产品生产消息:" + msg);
// channel.txCommit();
} catch (IOException e) {
e.printStackTrace();
// channel.txRollback();
} finally {
channel.close();
connection.close();
}
}
}
短信消费者
/**
* @author Administrator
*/
public class SmsConsumer {
private static String QUEUE_SMS = "sms";
private static String EXCHANGE = "sms_email";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
System.out.println("短信消费者");
//1.创建连接
Connection connection = ConnectionUtils.newConnection();
// 2.创建通道
final Channel channel = connection.createChannel();
// 3.声明队列
/**
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
* queue:这没什么好说的,队列名
*
* durable:是否持久化,那么问题来了,这是什么意思?持久化,指的是队列持久化到数据库中。在之前的博文中也说过,如果RabbitMQ服务挂了怎么办,队列丢失了自然是不希望发生的。持久化设置为true的话,即使服务崩溃也不会丢失队列
* exclusive:是否排外,what? 这又是什么呢。设置了排外为true的队列只可以在本次的连接中被访问,也就是说在当前连接创建多少个channel访问都没有关系,但是如果是一个新的连接来访问,对不起,不可以,下面是我尝试访问了一个排外的queue报的错。还有一个需要说一下的是,排外的queue在当前连接被断开的时候会自动消失(清除)无论是否设置了持久化
* autoDelete:这个就很简单了,是否自动删除。也就是说queue会清理自己。但是是在最后一个connection断开的时候
* 设置队列的其他一些参数
*/
channel.queueDeclare(QUEUE_SMS, false, false, false, null);
/**
* String queue, String exchange, String routingKey
*/
channel.queueBind(QUEUE_SMS, EXCHANGE, "message");
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msgString = new String(body, "UTF-8");
System.out.println("短信消费者获取消息:" + msgString);
}
};
// 4.设置应答模式,true的时候为自动应答,false为手动应答,需要处理
channel.basicConsume(QUEUE_SMS, true, defaultConsumer);
}
}
邮件消费者
public class EmailConsumer {
private static String QUEUE_EMAIL = "eamil";
private static String EXCHANGE = "sms_email";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
System.out.println("邮件消费者");
//1.创建连接
Connection connection = ConnectionUtils.newConnection();
// 2.创建通道
final Channel channel = connection.createChannel();
// 3.声明队列
/**
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
* queue:这没什么好说的,队列名
*
* durable:是否持久化,那么问题来了,这是什么意思?持久化,指的是队列持久化到数据库中。在之前的博文中也说过,如果RabbitMQ服务挂了怎么办,队列丢失了自然是不希望发生的。持久化设置为true的话,即使服务崩溃也不会丢失队列
* exclusive:是否排外,what? 这又是什么呢。设置了排外为true的队列只可以在本次的连接中被访问,也就是说在当前连接创建多少个channel访问都没有关系,但是如果是一个新的连接来访问,对不起,不可以,下面是我尝试访问了一个排外的queue报的错。还有一个需要说一下的是,排外的queue在当前连接被断开的时候会自动消失(清除)无论是否设置了持久化
* autoDelete:这个就很简单了,是否自动删除。也就是说queue会清理自己。但是是在最后一个connection断开的时候
* 设置队列的其他一些参数
*/
channel.queueDeclare(QUEUE_EMAIL, false, false, false, null);
channel.queueBind(QUEUE_EMAIL, EXCHANGE, "message");
// channel.txSelect();
try {
// int i = 1/0;
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msgString = new String(body, "UTF-8");
System.out.println("邮件消费者获取消息:" + msgString);
}
};
// 4.设置应答模式,true的时候为自动应答,false为手动应答,需要处理
channel.basicConsume(QUEUE_EMAIL, true, defaultConsumer);
// channel.txCommit();
} catch (Exception e) {
// channel.txRollback();
}
}
}
3.Topic模式
生产者
public class Producer {
private static String TOPIC_EXCHANGE = "topic";
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接
Connection connection = ConnectionUtils.newConnection();
// 2.创建通道
Channel channel = connection.createChannel();
//3.绑定的交换机 参数1交互机名称 参数2 exchange类型
channel.exchangeDeclare(TOPIC_EXCHANGE, "topic");
String msg = "Topic生产消息";
String msg1 = "Topic1生产消息";
String msg2 = "Topic2生产消息";
// 4.生产消息
channel.basicPublish(TOPIC_EXCHANGE, "topic.test", null, msg.getBytes());
System.out.println("Topic生产消息:" + msg1);
channel.basicPublish(TOPIC_EXCHANGE, "topic.test.test", null, msg1.getBytes());
System.out.println("Topic生产消息:" + msg1);
channel.basicPublish(TOPIC_EXCHANGE, "topic.test1", null, msg2.getBytes());
System.out.println("Topic生产消息:" + msg2);
}
短信消费者:topic.*,*代表匹配0个或多个单词
public class TopicSmsConsumer {
private static String QUEUE_SMS = "sms";
private static String EXCHANGE = "topic";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
System.out.println("短信消费者");
//1.创建连接
Connection connection = ConnectionUtils.newConnection();
// 2.创建通道
final Channel channel = connection.createChannel();
// 3.声明队列
/**
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
* queue:这没什么好说的,队列名
*
* durable:是否持久化,那么问题来了,这是什么意思?持久化,指的是队列持久化到数据库中。在之前的博文中也说过,如果RabbitMQ服务挂了怎么办,队列丢失了自然是不希望发生的。持久化设置为true的话,即使服务崩溃也不会丢失队列
* exclusive:是否排外,what? 这又是什么呢。设置了排外为true的队列只可以在本次的连接中被访问,也就是说在当前连接创建多少个channel访问都没有关系,但是如果是一个新的连接来访问,对不起,不可以,下面是我尝试访问了一个排外的queue报的错。还有一个需要说一下的是,排外的queue在当前连接被断开的时候会自动消失(清除)无论是否设置了持久化
* autoDelete:这个就很简单了,是否自动删除。也就是说queue会清理自己。但是是在最后一个connection断开的时候
* 设置队列的其他一些参数
*/
channel.queueDeclare(QUEUE_SMS, false, false, false, null);
/**
* String queue, String exchange, String routingKey
*/
channel.queueBind(QUEUE_SMS, EXCHANGE, "topic.*");
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msgString = new String(body, "UTF-8");
System.out.println("短信消费者获取消息:" + msgString);
}
};
// 4.设置应答模式,true的时候为自动应答,false为手动应答,需要处理
channel.basicConsume(QUEUE_SMS, true, defaultConsumer);
}
}
邮件消费者,topic.#,#代表匹配一个
public class TopicEamilConsumer {
private static String QUEUE_EMAIL = "eamil";
private static String EXCHANGE = "topic";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
System.out.println("邮件消费者");
//1.创建连接
Connection connection = ConnectionUtils.newConnection();
// 2.创建通道
final Channel channel = connection.createChannel();
// 3.声明队列
/**
* String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
* queue:这没什么好说的,队列名
*
* durable:是否持久化,那么问题来了,这是什么意思?持久化,指的是队列持久化到数据库中。在之前的博文中也说过,如果RabbitMQ服务挂了怎么办,队列丢失了自然是不希望发生的。持久化设置为true的话,即使服务崩溃也不会丢失队列
* exclusive:是否排外,what? 这又是什么呢。设置了排外为true的队列只可以在本次的连接中被访问,也就是说在当前连接创建多少个channel访问都没有关系,但是如果是一个新的连接来访问,对不起,不可以,下面是我尝试访问了一个排外的queue报的错。还有一个需要说一下的是,排外的queue在当前连接被断开的时候会自动消失(清除)无论是否设置了持久化
* autoDelete:这个就很简单了,是否自动删除。也就是说queue会清理自己。但是是在最后一个connection断开的时候
* 设置队列的其他一些参数
*/
channel.queueDeclare(QUEUE_EMAIL, false, false, false, null);
channel.queueBind(QUEUE_EMAIL, EXCHANGE, "topic.#");
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msgString = new String(body, "UTF-8");
System.out.println("邮件消费者获取消息:" + msgString);
}
};
// 4.设置应答模式,true的时候为自动应答,false为手动应答,需要处理
channel.basicConsume(QUEUE_EMAIL, true, defaultConsumer);
}
}