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);
  }
}
 
posted @ 2023-03-15 23:33  ENU  阅读(27)  评论(0编辑  收藏  举报