rabbitmq-demo
demo
ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。ConnectionFactory为Connection的制造工厂。 Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等。
ConnectionFactory
Connection
Channel
下面是一个 有发送确认和消费确认的一个发送到接收的简要流程
api : https://rabbitmq.github.io/rabbitmq-java-client/api/current/
1 导入依赖
导入上面这个依赖就已近依赖传递的导入了下面的jar了
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<!-- <dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.4.3</version>
</dependency>-->
2.发消息
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
//1.连接rabbit并获取channel
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("47.96.107.200");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//2.声明交换机,属性:交换机名称,交换机类型,是否持久化,是否自动删除,其他属性
//direct topic fanout headers
channel.exchangeDeclare("exchange-name", "direct", false, false, null);
//3.声明队列,属性:队列名称,是否持久队列,是否独占队列,是否自动删除队列,队列的其他属性
//声明队列是幂等的 - 只有在它不存在的情况下才会创建它
String queue = channel.queueDeclare("queue-name", false, false, false, null).getQueue();
System.out.println(queue);
//4.队列绑定交换机
channel.queueBind(queue, "exchange-name", "key");
//5.启用发送确认
channel.confirmSelect();
//6.添加发送确认监听器
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long l, boolean b) throws IOException {
System.out.println("ack+" + l);//肯定确认
}
@Override
public void handleNack(long l, boolean b) throws IOException {
System.out.println("nack+" + l);//否定确认
}
});
while (true) {//循环发送
//7.发送消息 属性:交换机名称,路由值,是否强制,是否立即,其他属性,消息内容
//这里通过MessageProperties.PERSISTENT_TEXT_PLAIN 将消息标记为持久性,会写入磁盘
channel.basicPublish("exchange-name", "key", false, false, MessageProperties.PERSISTENT_TEXT_PLAIN, "谢建武".getBytes());
System.out.println("发送了");
Thread.sleep(2000);
}
//8.关闭连接
/* channel.close();
connection.close();*/
}
}
3.收消息
public class Consumer {
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
//1.连接rabbit并获取channel
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("47.96.107.200");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 2.设置消费者在确认前获取消息的最多数量
channel.basicQos(1);
//3.消费消息
channel.basicConsume("queue-name", new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(consumerTag + "---" + "消息内容:" + new String(body));
//4.消费确认
channel.basicAck(envelope.getDeliveryTag(), false);
//拒绝,参数:交付标签,是否多条,是否重新加入队列,false就会丢弃
//channel.basicNack(envelope.getDeliveryTag(),false,true);
}
});
//5.关闭连接
/* channel.close();
connection.close();*/
}
}
4.可能遇见的问题
1.阿里云端口5672没开放
2.创建ConnectionFactory时发现总是超时
经排查,发现是创建ConnectionFactory时使用的guest用户,而guest用户只能用作本地登录的。需要新建一个用户,并赋予对应的权限。对应的命令为:
rabbitmqctl add_user root root
rabbitmqctl set_user_tags root administrator
rabbitmqctl set_permissions -p / root ".*" ".*" ".*"
//查看用户命令
rabbitmqctl list_users
添加完用户后还需要对RabbitMQ服务进行重启
重启rabbitmq服务通过两个命令来实现:
rabbitmqctl stop :停止rabbitmq
rabbitmq-server restart : 重启rabbitmq
rabbitmqctl常用命令:
https://blog.csdn.net/qq_40325734/article/details/103111397
和spring整合
ReturnCallback和ConfirmCallback区别
1.如果消息没有到exchange,则confirm回调,ack=false
2.如果消息到达exchange,则confirm回调,ack=true
3.exchange到queue成功,则不回调return
4.exchange到queue失败,则回调return(需设置mandatory=true,否则不回调,消息就丢了),此时confirm回调也是ack=true
1.导入依赖
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
2.配置文件
rabbitmq.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<!--1. 配置connection-factory连接工厂-->
<rabbit:connection-factory id="connectionFactory" host="47.96.107.200" port="5672" username="root" password="root"
publisher-confirms="true" publisher-returns="true"/>
<!--2. 配置admin 这样生产者的queue和exchange才会在rabbitmq服务器上生成-->
<rabbit:admin connection-factory="connectionFactory"/>
<!--3. 配置队列 -->
<rabbit:queue name="queue-name" durable="true" auto-delete="true" exclusive="false"/>
<!-- 想将消息进行持久化,只需要将交换机和队列持久化就可以了-->
<!-- 4.定义direct exchange,绑定队列 -->
<rabbit:direct-exchange name="exchange-name" durable="true" auto-delete="true">
<rabbit:bindings>
<rabbit:binding queue="queue-name" key="key"></rabbit:binding>
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- 5.定义消息模板用户发送数据或接收数据,不过一般只用于发送消息(生产消息),
并配置发送确认confirm-callback和return-callback,且须在步骤1中也开启 -->
<rabbit:template id="defaultTemplate" connection-factory="connectionFactory" exchange="exchange-name"
mandatory="true"
confirm-callback="confirmListener"
return-callback="returnListener"
message-converter="jsonMessageConverter"
correlation-key=""
/>
<!-- 6.定义消息监听容器(消费消息)-->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" concurrency="1" prefetch="1"
message-converter="jsonMessageConverter">
<rabbit:listener queue-names="queue-name" ref="rabbitConsumer"/>
</rabbit:listener-container>
<!--7.指定消息转换器(不指定是使用默认的SimpleMessageConverter),并在5.6.步骤中配置-->
<bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />
</beans>
3.发送
发送确认需要在配置文件1和5中配置下
@Component
public class RabbitProducer {
/* 备注1
@Resource(name = "defaultTemplate")
private RabbitTemplate defaultTemplate;*/
@Resource(name = "defaultTemplate")
private AmqpTemplate defaultTemplate;
public void send() {
System.out.println("1.发送消息-----:" + "谢谢谢谢");
HashMap<String, String> map = new HashMap<>();
map.put("name", "谢建武");
map.put("sex", "男");
defaultTemplate.convertAndSend("key", map);
/*
correlationData需要使用RabbitTemplate类型发送,上面备注1
CorrelationData correlationData = new CorrelationData("56");
defaultTemplate.convertAndSend("key", map,correlationData);*/
}
}
4.接收
@Component("rabbitConsumer")
public class RabbitConsumer implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
String messageBody = new String(message.getBody(), "utf-8");
System.out.println(messageBody);
System.out.println("3.消费消息------------:" + messageBody);
Thread.sleep(3000);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
5.发送确认回调
@Component("confirmListener")
public class ConfirmCallbackListener implements RabbitTemplate.ConfirmCallback {
@Override
//确认回调
public void confirm(CorrelationData correlationData, boolean b, String s) {
System.out.println("2.发送确认----" + "是否成功:" + b + "关联数据:" + correlationData);
}
}
6.失败回调
@Component(value = "returnListener")
public class ReturnCallbackListener implements RabbitTemplate.ReturnCallback {
@Override
//交换机到queue失败回调,使用return-callback时必须设置mandatory为true
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
System.out.println("发送返回");
System.out.println(message);
System.out.println(i + " " + s + " " + s1 + " " + s2);
}
}