RabbitMQ原生应用
依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.4.3</version>
</dependency>
Linux配置:
# 设置服务,开机自动启动
systemctl enable rabbitmq-server
# 启动服务
systemctl start rabbitmq-server
# 开启管理界面插件
rabbitmq-plugins enable rabbitmq_management
# 防火墙打开 15672 管理端口
firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --reload
#执行完成后重启一遍
systemctl restart rabbitmq-server
访问控制台
http://192.168.64.140:15672
添加初始用户
# 添加用户
rabbitmqctl add_user admin admin
# 新用户设置用户为超级管理员
rabbitmqctl set_user_tags admin administrator
然后去后台加入处理权限
完成服务端配置后,需要打开客户端连接端口
# 打开客户端连接端口
firewall-cmd --zone=public --add-port=5672/tcp --permanent
firewall-cmd --reload
生产者Demo
//1.建立连接
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setVirtualHost("/abc");
//5672是客户端通信端口
//如果默认端口就是5672,这个端口可以省略
f.setPort(5672);
f.setUsername("admin");
f.setPassword("admin");
//通信采用TCP通信协议,由于创建TCP对象效率很低,所以
Connection conn = f.newConnection();
//为了区分不同Consumer发送的信息,所以就需要创建一个Channel
//当Consumer离线时,可以销毁Channel
Channel c = conn.createChannel();
//2.向服务器发送指令,要求服务器准备好队列:helloworld
//定义队列
//1.队列名,2.是否持久队列,3.是否排他队列
//4.是否自动删除,5.其他参数属性
c.queueDeclare("helloworld",false,false,false,null);
//3.向指定队列发送数据
//第四个参数是发送的消息数据,必须是byte[]数组
//1.先不解释,2.队列名,3.其他参数属性配置,4.发送消息内容(Byte[])
c.basicPublish("", "helloworld", null, ("abc").getBytes());
System.out.println("消息已经发送!");
c.close();
conn.close();
消费者Demo
ConnectionFactory f = new ConnectionFactory();
f.setHost("192.168.64.140");
f.setPort(5672);
f.setUsername("admin");
f.setPassword("admin");
Connection conn = f.newConnection();
Channel c = conn.createChannel();
//参数说明:
//1.队列名,2.是否是持久队列,3.是否是消费者独占队列
//4.没有消费者时是否自动删除,5.其他的参数属性配置
c.queueDeclare("helloworld",false,false,false,null);
//创建回调对象
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
byte[] a = message.getBody();
String msg = new String(a);
System.out.println("收到!消息内容:"+msg);
c.basicAck(message.getEnvelope().getDeliveryTag(), false);
}
};
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
// TODO Auto-generated method stub
}
};
//basicConsume的参数说明
//1.名称
//2.true/false,自动ACK/手动ACK,false表示从RabbitMQ拿走数据后仍然保存为缓存状态,发送回执后才会从RabbitMQ删除
//如果消费者宕机,RabbitMQ会把未处理完的消息发送到其他消费者
c.basicConsume("helloworld", false, deliverCallback,cancelCallback);
消费者需要注意的是,可以用匿名内部类的方式创建回调对象,也可以用Spring注入的方式创建对象
Channel.queueDeclare()
参数说明:
1.消息队列名称
2.定义该队列是否是持久化队列,注意无法修改已存在的消息队列,需要新指定消息队列
3.是否是消费者独占队列
4.没有消费者时是否自动删除
5.其他的参数属性配置
Channel.basicPublish()
参数说明:
1.写空串就是默认交换机,direct,可以改为自定义交换机
2.消息队列名称
3.其他参数属性,例:MessageProperties.PERSISTENT_TEXT_PLAIN:持久化为纯文本文件
4.消息内容,注意格式为Byte[]数组
Channel.basicConsume()
参数说明:
-
消息队列名称
-
true/false,自动ACK/手动ACK,false表示从RabbitMQ拿走数据后仍然保存为缓存状态,发送回执后才会从RabbitMQ删除
如果消费者宕机,RabbitMQ会把未处理完的消息发送到其他消费者 -
deliverCallback:接收消息后通过该对象执行处理,必须有,可以创建匿名内部类实现
-
cancelCallback:取消后桶盖该对象执行处理,必须有,可以创建匿名内部类实现
DeliverCallback
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
byte[] a = message.getBody();
String msg = new String(a);
System.out.println("收到!消息内容:"+msg);
for (int i = 0 ; i < msg.length() ; i++) {
if('.' == msg.charAt(i)) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
c.basicAck(message.getEnvelope().getDeliveryTag(), false);
System.out.println("消息处理结束");
}
CancelCallback
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
// TODO Auto-generated method stub
}
};
其他
端口说明:
- 4369 – erlang发现口
- 5672 – client端通信口
- 15672 – 管理界面ui端口
- 25672 – server间内部通信口
处理消息和等待接受消息,都是在独立的线程中进行的
交换机
可以指定交换机Type:
direct,fanout,headers,topic
交换机是不存储数据的,如果没有消费者接收数据,数据就会直接丢弃
群发一般用fanout
给fanout交换机指定一个名称:logs
channel.exchangeDeclare("logs", "fanout");