一、基于docker安装(Centos下)
1、查询一下镜像库
docker search rabbitmq:management
2、拉取镜像,并查看本地是否存在
docker pull rabbitmq:management
3、启动rabbitmq,这里开启两个端口映射,5672是rabbitmq默认的客户端连接端口,15672是web管理界面的端口。-d 是后台运行,--name 是给容器取别名便于后面查找,最后是镜像id。启动后查看运行状态
docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq db322a6c3b84
二、rabbitMQ管理
1、正确安装之后,访问管理界面,地址是ip:15672,会出现该界面,默认用guest/guest可以登录
三、代码连接(为了方便测试,生产消费端都写在一个文件,这样不好,真正使用请自行分离。)
调试过程中遇到一个问题(received 'fanout' but current is 'direct'。。。。。),由于我是用的docker部署的rabbitmq,解决方法如下:
#进入该容器
docker exec -it f6ccd6482b3a /bin/bash
#查看队列
rabbitmqctl list_queues
#停止
rabbitmqctl stop_app
#清除数据
rabbitmqctl reset
#启动
rabbitmqctl start_app
1、单发送单队列单接收(simple 简单模式),一个发送一个接收
public class RabbitmqSimple {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String QUEUE_NAME = "queue_name";
public static void main(String[] args) throws Exception{
producer();
consumer();
}
//生产者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//创建持久化、非自动删除的队列
channel.queueDeclare(QUEUE_NAME,true,false,false,null);
String message = "project_start";
System.out.println("发送消息");
//发送消息
channel.basicPublish(
"",
QUEUE_NAME,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
channel.close();
connection.close();
}
//消费者
public static void consumer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//客户端最多接受未被ack的消息个数
channel.basicQos(50);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示该消息已经被消费
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(QUEUE_NAME,false,defaultConsumer);//手动模式,消费者成功消费后服务端不会自动标记为成功消费,需要将状态传回服务端手动更新
// channel.basicConsume(QUEUE_NAME,true,defaultConsumer);//自动模式,消费者获取消息后服务端自动标记为成功消费
TimeUnit.SECONDS.sleep(5);
channel.close();
connection.close();
/**另一种方式获取,但方法已经不推荐**/
// QueueingConsumer consumer = new QueueingConsumer(channel);
// channel.basicConsume(QUEUE_NAME,consumer);
// while (true){
// QueueingConsumer.Delivery delivery = consumer.nextDelivery();
// System.out.println(new String(delivery.getBody()));
// }
/**另一种方式获取,但方法已经不推荐**/
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}
2、单发送单队列多接收(work,工作模式),一个发送多个端一起处理消息
public class RabbitmqWork {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String QUEUE_NAME = "queue_name";
public static void main(String[] args) throws Exception{
producer();
consumer(1);
consumer(2);
}
//生产者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//创建持久化、非自动删除的队列
channel.queueDeclare(QUEUE_NAME,true,false,false,null);
System.out.println("发送消息");
for(int i=0;i<10;i++){
//发送消息
String message = "project_start:" + i;
channel.basicPublish(
"",
QUEUE_NAME,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
}
channel.close();
connection.close();
}
//消费者
public static void consumer(int cons) throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//客户端最多接受未被ack的消息个数,现在设置1,同一时刻只接收一个,处理完返回成功再继续接收
channel.basicQos(1);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(cons + "消费者:"+ new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示该消息已经被消费
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(QUEUE_NAME,false,defaultConsumer);//手动模式,消费者成功消费后服务端不会自动标记为成功消费,需要将状态传回服务端手动更新
TimeUnit.SECONDS.sleep(5);
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}
3、单发送多队列多接收(Publish/Subscribe 发布、订阅模式),假如每个消费者一个队列则可实现收到相同信息(广播)
public class RabbitmqPublish {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String TYPE = "fanout";
private static final String EXCHANGE_NAME = "exchange_name";
private static final String QUEUE_NAME = "queue_name";
private static final String QUEUE_NAME2 = "queue_name2";
public static void main(String[] args) throws Exception{
producer();
consumer(QUEUE_NAME);
consumer(QUEUE_NAME2);
}
//生产者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//创建持久化、非自动删除的交换器,Exchange有4种类型:direct(默认),fanout,topic,和headers,这里用fanout 广播消息,不需要使用queue
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
String message = "project_start";
System.out.println("发送消息");
//发送消息
channel.basicPublish(
EXCHANGE_NAME,
"",
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
channel.close();
connection.close();
}
//消费者
public static void consumer(String queue) throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//交换机
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
//创建持久化、非自动删除的队列
channel.queueDeclare(queue,true,false,false,null);
//交换器和队列进行绑定,注意这里不同消费者交换器名字一样,但队列不同
channel.queueBind(queue,EXCHANGE_NAME,"");
channel.basicQos(1);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(queue + ":" + new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示该消息已经被消费
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(queue,false,defaultConsumer);//手动模式,消费者成功消费后服务端不会自动标记为成功消费,需要将状态传回服务端手动更新
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}
4、消费者根据不同路由key(Routing 路由模式),在第三点的基础上把type改成direct,发送消息加了routing key
public class RabbitmqRouting {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String TYPE = "direct";
private static final String EXCHANGE_NAME = "exchange_name";
private static final String QUEUE_NAME = "queue_name";
private static final String QUEUE_NAME2 = "queue_name2";
private static final String ROUTING_KEY = "routing_key";
private static final String ROUTING_KEY2 = "routing_key2";
public static void main(String[] args) throws Exception{
producer();
consumer(QUEUE_NAME,ROUTING_KEY);
consumer(QUEUE_NAME2,ROUTING_KEY2);
}
//生产者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//创建持久化、非自动删除的交换器,Exchange有4种类型:direct(默认),fanout,topic,和headers,这里用fanout 广播消息,不需要使用queue
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
String message = "project_start";
System.out.println("发送消息");
//发送消息
channel.basicPublish(
EXCHANGE_NAME,
ROUTING_KEY,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
//另一个路由
String message2 = "project_start2";
channel.basicPublish(
EXCHANGE_NAME,
ROUTING_KEY2,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message2.getBytes()
);
channel.close();
connection.close();
}
//消费者
public static void consumer(String queue,String routing) throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//交换机
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
//创建持久化、非自动删除的队列
channel.queueDeclare(queue,true,false,false,null);
//交换器和队列进行绑定,注意这里不同消费者交换器名字一样,但队列不同和路由key不一样
channel.queueBind(queue,EXCHANGE_NAME,routing);
channel.basicQos(1);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(queue + ":" + new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示该消息已经被消费
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(queue,false,defaultConsumer);//手动模式,消费者成功消费后服务端不会自动标记为成功消费,需要将状态传回服务端手动更新
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}
5、两端都按通配符匹配(Topics 主题模式),在第三点的基础上把type改成topic,发送消息的routing key去匹配binding key,比如 routing.* 这种规则,也可以用 # ,* 是匹配一个单词,# 是匹配多个单词
public class RabbitmqTopic {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String TYPE = "topic";
private static final String EXCHANGE_NAME = "exchange_name";
private static final String QUEUE_NAME = "queue_name";
private static final String QUEUE_NAME2 = "queue_name2";
private static final String ROUTING_KEY = "routing.key";
private static final String ROUTING_KEY2 = "routing.key2";
private static final String BINDING_KEY_COMMON = "routing.*";
public static void main(String[] args) throws Exception{
producer();
consumer(QUEUE_NAME);
consumer(QUEUE_NAME2);
}
//生产者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//创建持久化、非自动删除的交换器,Exchange有4种类型:direct(默认),fanout,topic,和headers,这里用fanout 广播消息,不需要使用queue
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
System.out.println("发送消息");
//发送消息
String message = "project_start";
channel.basicPublish(
EXCHANGE_NAME,
ROUTING_KEY,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
//另一个路由
String message2 = "project_start2";
channel.basicPublish(
EXCHANGE_NAME,
ROUTING_KEY2,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message2.getBytes()
);
channel.close();
connection.close();
}
//消费者
public static void consumer(String queue) throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//交换机
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
//创建持久化、非自动删除的队列
channel.queueDeclare(queue,true,false,false,null);
//交换器和队列进行绑定,注意这里不同消费者交换器名字一样,但队列不同,路由采用匹配方式
channel.queueBind(queue,EXCHANGE_NAME,BINDING_KEY_COMMON);
channel.basicQos(1);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(queue + ":" + new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示该消息已经被消费
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(queue,false,defaultConsumer);//手动模式,消费者成功消费后服务端不会自动标记为成功消费,需要将状态传回服务端手动更新
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}