RabbitMQ入门
文章目录
windows中打开rabbitmq_server-3.9.14的sbin目录,进入cmd
rabbitmqctl stop 停止服务
rabbitmq-server -detached 后台启动(可以关闭cmd窗口)
生产者—交换机—通道channel—queue----消费者
helloworld
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("123");
//获取连接对象
Connection connection = connectionFactory.newConnection();
//通过连接中的通道
Channel channel = connection.createChannel();
//通道绑定对应消息队列
//参数1:队列名字 如果队列不存在自动创建
//参数2:用来定义队列特性是否要持久化 true持久化队列 false不持久化
//参数3:exclusive 是否独占队列
// 参数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();
}
}
第一种模式(直连)
消费者:
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("123");
//创建连接对象
// Connection connection = connectionFactory.newConnection();
Connection connection = RabbitMQUtils.getConnection();
//创建通道
Channel channel = connection.createChannel();
//通道绑定对象
channel.queueDeclare("hello",false,false,false,null);
//参数1:消费哪个队列的消息 队列名称
// 参数2:开启消息的自动确认机制
// 参数3:消费时的回调接口
channel.basicConsume("hello",true,new DefaultConsumer(channel){
//最后一个参数:消息队列中取出的消息
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();
RabbitMQUtils.closeConnectionAndChanel(channel,connection);
}
}
工具类:
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("123");
}
public static Connection getConnection(){
try {
//创建连接对象
Connection connection = connectionFactory.newConnection();
//创建通道
Channel channel = connection.createChannel();
return connection;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void closeConnectionAndChanel(Channel channel,Connection conn){
try {
if(channel!=null)
channel.close();
if(conn!=null)
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
同一个通道channel可以发送到不同的队列
//注意第一个创建并绑定的队列是aa
//但发送到的队列是hello
//通道绑定对应消息队列
//参数1:队列名字 如果队列不存在自动创建
//参数2:用来定义队列特性是否要持久化 true持久化队列 false不持久化
//参数3:exclusive 是否独占队列
// 参数4:autoDelete 是否在消费完成后自动删除队列
// 参数5:额外附加参数
channel.queueDeclare("aa",false,false,false,null);
//发布消息
//参数1:交换机名称 参数2:队列名称 参数3:传递消息额外设置 参数4:消息的具体内容
channel.basicPublish("","hello",null,"hello rabbitmq".getBytes());
//MessageProperties.PERSISTENT_TEXT_PLAIN : 队列里面的消息也要持久化
channel.basicPublish("","aa", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello rabbitmq".getBytes());
消费者和生产者的队列创建参数要一样
第二种模式(work queue)
多个消费者 绑定 一个队列
work模型中,消费者是轮流获取队列中的消息
public class Customer1 {
public static void main(String[] args) throws IOException {
//获取连接
Connection connection = RabbitMQUtils.getConnection();
final Channel channel = connection.createChannel();
//一次只接收1条消息
channel.basicQos(1);
channel.queueDeclare("work",true,false,false,null);
//参数2:自动确认
//rabbitmq会自动分配,如5个完整数据,消费了3个数据,结果自己宕机了,则2个消息丢失
//我们希望没有消费的消息交给其他Customer
channel.basicConsume("work",false,new DefaultConsumer(channel){
//最后一个参数:消息队列中取出的消息
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1 = "+new String(body));
//手动确认 参数1:手动确认消息标识 参数2;false 每次确认一个
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
}
}
public class Customer2 {
public static void main(String[] args) throws IOException {
//获取连接
Connection connection = RabbitMQUtils.getConnection();
final Channel channel = connection.createChannel();
channel.basicQos(1);
channel.queueDeclare("work",true,false,false,null);
channel.basicConsume("work",false,new DefaultConsumer(channel){
//最后一个参数:消息队列中取出的消息
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者2 = "+new String(body));
//手动确认 参数1:手动确认消息标识 参数2;false 每次确认一个
channel.basicAck(envelope.getDeliveryTag(),false);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
生产者:
public class Provider {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("work",true,false,false,null);
for (int i = 0; i < 20; i++) {
//生产消息
channel.basicPublish("","work",null,(i+" hello work queue").getBytes());
}
//关闭资源
RabbitMQUtils.closeConnectionAndChanel(channel,connection);
}
}
第三种模式(fanout)扇出,也称 广播
需要交换机(前两种模式使用的默认的交换机)
交换机决定把消息发给哪个队列,生产者无法决定
由于是广播,所以生产者生成一条,消费者都可以拿到
生产者:
public class Provider {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//将通道声明指定交换机 参数1:交换机名字 参数2:交换机类型
channel.exchangeDeclare("logs","fanout");
//发送消息 参数2:路由键 参数3:props
channel.basicPublish("logs","",null,"fanout type message".getBytes());
//释放资源
RabbitMQUtils.closeConnectionAndChanel(channel,connection);
}
}
消费者1:
public class Customer1 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//通道绑定交换机
channel.exchangeDeclare("logs","fanout");
//通道绑定队列 临时队列
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
channel.queueBind(queueName,"logs","");
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
//最后一个参数:消息队列中取出的消息
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1 = "+new String(body));
}
});
}
}
消费者2:
public class Customer2 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//通道绑定交换机
channel.exchangeDeclare("logs","fanout");
//通道绑定队列 临时队列
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
channel.queueBind(queueName,"logs","");
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
//最后一个参数:消息队列中取出的消息
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者2 = "+new String(body));
}
});
}
}
第四种情况 路由(Routing)
Routing之订阅模式-Direct(直连)
在Fanout模式中,一条信息会被所有订阅的队列消费,但是,在某些场景下,我们希望不同的消息被不同的队列消费,这是就要用到Direct类型的Exchangel
队列和交换机的绑定需要指定一个路由key
生产者:定义路由key
//发送消息 参数2:路由键 参数3:props
channel.basicPublish("logs","",null,"fanout type message".getBytes());
第五种情况 动态路由 topics
通配符
注意这里生产者创建交换机和消费者绑定交换机时 交换机类型是 topic
只是在生产者绑定路由键时加上*或#
消费者1:
public class Customer1 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//声明交换机以及交换机类型
channel.exchangeDeclare("topics","topic");
String queue = channel.queueDeclare().getQueue();
//绑定队列和交换机 动态通配符route key
channel.queueBind(queue,"topics","user.*");
//消费消息
channel.basicConsume(queue,true,new DefaultConsumer(channel){
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1 = "+new String(body));
}
});
}
}
消费者2:
public class Customer2 {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//声明交换机以及交换机类型
channel.exchangeDeclare("topics","topic");
String queue = channel.queueDeclare().getQueue();
//绑定队列和交换机 动态通配符route key
channel.queueBind(queue,"topics","user.#");
//消费消息
channel.basicConsume(queue,true,new DefaultConsumer(channel){
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者2 = "+new String(body));
}
});
}
}
生产者:
public class Provider {
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//声明交换机以及交换机类型 topic
channel.exchangeDeclare("topics","topic");
//发布消息
String routekey="user.save.findAll";
channel.basicPublish("topics",routekey,null,("这里是topic动态路由模型,routekey = "+routekey).getBytes());
RabbitMQUtils.closeConnectionAndChanel(channel,connection);
}
}
整合SpringBoot
创建springboot
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
spring:
application:
name: rabbitmq-springboot
rabbitmq:
host: 127.0.0.1
port: 5672
password: 123
username: ems
virtual-host: /ems
RabbitTemplate 用来简化操作,使用的时候直接在项目中注入
类似于RedisTemplate
HelloWorld
消费者:
@Component //持久化 非独占 不是自动删除队列
@RabbitListener(queuesToDeclare = @Queue(value = "hello"))
public class HelloCustomer {
@RabbitHandler
public void receive1(String message){
System.out.println("-------message = "+message);
}
}
生产者:
@SpringBootTest
class RabbitmqSpringbootApplicationTests {
//注入RabbitTemplate
@Autowired
private RabbitTemplate rabbitTemplate;
// 队列的创建和消费者、发布者没有任何关系,有需要就可以创建,还有这里的routingkey和queueName是完全不同的两个概念,这里他都混为一谈了,很容易让大家混淆
@Test
void contextLoads() {
rabbitTemplate.convertAndSend("hello","hello world");
}
}
如果没有消费者只有生产者,队列不会出现
work queue
@Test
public void testWork(){
for (int i = 0; i < 10; i++) {
rabbitTemplate.convertAndSend("work","work模型 "+i);
}
}
@Component
public class WorkCustomer {
//第一个消费者
@RabbitListener(queuesToDeclare = @Queue("work"))
public void receive1(String message){
System.out.println("message1 = "+message);
}
//第二个消费者
@RabbitListener(queuesToDeclare = @Queue("work"))
public void receive2(String message){
System.out.println("message2 = "+message);
}
}
fanout
//fanout广播
@Test
public void testFanout(){
rabbitTemplate.convertAndSend("logs","","fanout广播 ");
}
@Component
public class FanoutCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,//创建临时队列
exchange = @Exchange(value = "logs",type = "fanout")//绑定交换机
)
})
public void receive1(String message){
System.out.println("message1 = "+message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,//创建临时队列
exchange = @Exchange(value = "logs",type = "fanout")//绑定交换机
)
})
public void receive2(String message){
System.out.println("message2 = "+message);
}
}
路由route
//route 路由
@Test
public void testRoute(){
rabbitTemplate.convertAndSend("directs","error","发送info的key的路由信息");
}
@Component
public class RouteCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "directs",type = "direct"), //指定交换机名称和类型
key = {"info","error","warn"}
)
})
public void receive1(String message){
System.out.println("-------message1 = "+message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "directs",type = "direct"), //指定交换机名称和类型
key = {"info"}
)
})
public void receive2(String message){
System.out.println("-------message2 = "+message);
}
}
动态路由
//topic
@Test
public void testTopic(){
rabbitTemplate.convertAndSend("topics","user.save","user.save的路由信息");
}
@Component
public class TopicCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(type = "topic",value = "topics"),
key = {"user.*"}
)
})
public void receive1(String message){
System.out.println("-------message1 = "+message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(type = "topic",name = "topics"),
key = {"user.#"}
)
})
public void receive2(String message){
System.out.println("-------message2 = "+message);
}
}