• eyb:RubbitMQ学习2



    目录:

    (1)路由队列

    (2)主题队列

    (3)RPC队列

    (4)事务

    (5)同步确认模式

    (6) 异步确认模式

    (7) SpringAMQP


    (1)路由队列

    上面将了发布订阅模式,本质上用的交换机的广播模式:

    生产者发送消息给交换机,然后由交换机发给绑定他的一个队列,然后被不同的队列后面的消费者所接收,这样我们发送一条消息,消费者接收到的都是一条消息,那么现在又有一个需求,比如会员制,比如说:微信公众号,只有开通会员的才能看的文章,可以推给会员用户,没开会员的职能看一些普通文章。那么发布订阅就不行了,它无法根据文章的需求,那些消费者可以接收,那些不能接收,我们就要有这样一条消息,这两个消费者能接收,那两个消费者不能接收,还有一条消息4个消费者都能接收这种区分开来,就用来另外一种模式路由模式:

    绑定一个路由key:交换机通过路由key来传给对应的队列

     

    创建者:

    1. package com.xxxx.direct.send;
    2. import com.rabbitmq.client.BuiltinExchangeType;
    3. import com.rabbitmq.client.Channel;
    4. import com.rabbitmq.client.Connection;
    5. import com.rabbitmq.client.ConnectionFactory;
    6. import java.nio.charset.StandardCharsets;
    7. /*
    8. * 路由队列:消息的生产者
    9. *
    10. * */
    11. public class Send {
    12. //定义交换机名称
    13. private final static String EXCHANGE_NAME = "exchange_direct";
    14. public static void main(String[] argv) throws Exception {
    15. // 创建连接工厂
    16. ConnectionFactory factory=new ConnectionFactory();
    17. //相关配置
    18. factory.setHost("192.168.23.129");
    19. factory.setUsername("yeb");
    20. factory.setVirtualHost("/yeb");
    21. factory.setPassword("123456");
    22. factory.setPort(5672);
    23. try(
    24. //连接工厂创建连接
    25. Connection connection=factory.newConnection();
    26. //创建信道
    27. Channel channel = connection.createChannel()){
    28. //绑定交换机
    29. channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
    30. // 消息内容
    31. String infomessage = "普通信息!";
    32. String errormessage = "错误信息!";
    33. String waringmessage = "警告信息!";
    34. //路由
    35. String infoRoutingKey="info";
    36. String errorRoutingKey="error";
    37. String waringRoutingKey="waring";
    38. //发送消息 第一个参数是交换机,第二个:路由key 第三个:对应的参数 第四个:消息的实体
    39. channel.basicPublish(EXCHANGE_NAME,infoRoutingKey, null, infomessage.getBytes(StandardCharsets.UTF_8));
    40. channel.basicPublish(EXCHANGE_NAME,errorRoutingKey, null, errormessage.getBytes(StandardCharsets.UTF_8));
    41. channel.basicPublish(EXCHANGE_NAME,waringRoutingKey, null, waringmessage.getBytes(StandardCharsets.UTF_8));
    42. System.out.println(" [x] Sent '" + infomessage + "'");
    43. System.out.println(" [x] Sent '" + errormessage + "'");
    44. System.out.println(" [x] Sent '" + waringmessage + "'");
    45. }
    46. }
    47. }

     消费者1:让他只接受错误消息

    1. package com.xxxx.direct.recv;
    2. import com.rabbitmq.client.*;
    3. /*
    4. * 路由队列:消息的消费者
    5. *
    6. * */
    7. public class Recv01 {
    8. //定义队列名称
    9. private final static String EXCHANGE_NAME = "exchange_direct";
    10. public static void main(String[] argv) throws Exception {
    11. // 创建连接工厂
    12. ConnectionFactory factory=new ConnectionFactory();
    13. //相关配置
    14. factory.setHost("192.168.23.129");
    15. factory.setUsername("yeb");
    16. factory.setVirtualHost("/yeb");
    17. factory.setPassword("123456");
    18. factory.setPort(5672);
    19. //连接工厂创建连接
    20. Connection connection=factory.newConnection();
    21. //创建信道
    22. Channel channel = connection.createChannel();
    23. //绑定交换机
    24. channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
    25. //获取队列(排他队列)
    26. String queueName=channel.queueDeclare().getQueue();
    27. String errorRoutingKey="error";//路由key,只让他接收错误信息
    28. //绑定队列和交换机、
    29. channel.queueBind(queueName,EXCHANGE_NAME,errorRoutingKey);
    30. System.out.println("[*] Waitint for message .To exit press CTRL+C");
    31. DeliverCallback deliverCallback=(consumerTag, delivery) -> {
    32. String message=new String(delivery.getBody(),"UTF-8");
    33. System.out.println(" [x] Received '" + message + "'");
    34. };
    35. //监听队列消费消息 第二个参数:消息自动回值告诉生产者收到消息
    36. channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {
    37. });
    38. }
    39. }

    消费者2:接收3条消息 

    1. package com.xxxx.direct.recv;
    2. import com.rabbitmq.client.*;
    3. /*
    4. * 路由队列:消息的消费者
    5. *
    6. * */
    7. public class Recv02 {
    8. //定义队列名称
    9. private final static String EXCHANGE_NAME = "exchange_direct";
    10. public static void main(String[] argv) throws Exception {
    11. // 创建连接工厂
    12. ConnectionFactory factory=new ConnectionFactory();
    13. //相关配置
    14. factory.setHost("192.168.23.129");
    15. factory.setUsername("yeb");
    16. factory.setVirtualHost("/yeb");
    17. factory.setPassword("123456");
    18. factory.setPort(5672);
    19. //连接工厂创建连接
    20. Connection connection=factory.newConnection();
    21. //创建信道
    22. Channel channel = connection.createChannel();
    23. //绑定交换机
    24. channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
    25. //获取队列(排他队列)
    26. String queueName=channel.queueDeclare().getQueue();
    27. String infoRoutingKey="info";
    28. String errorRoutingKey="error";
    29. String waringRoutingKey="waring";
    30. //绑定队列和交换机
    31. channel.queueBind(queueName,EXCHANGE_NAME,infoRoutingKey);
    32. channel.queueBind(queueName,EXCHANGE_NAME,errorRoutingKey);
    33. channel.queueBind(queueName,EXCHANGE_NAME,waringRoutingKey);
    34. System.out.println("[*] Waitint for message .To exit press CTRL+C");
    35. DeliverCallback deliverCallback=(consumerTag, delivery) -> {
    36. String message=new String(delivery.getBody(),"UTF-8");
    37. System.out.println(" [x] Received '" + message + "'");
    38. };
    39. //监听队列消费消息 第二个参数:消息自动回值告诉生产者收到消息
    40. channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {
    41. });
    42. }
    43. }

    启动消费者、消息的创建者:

    发现交换机多了:direct:

     发送者:

     消费者1:

    消费者2:

    与发布与订阅最大的区别是加了路由key,通过路由key去绑定不同的队列,然后发消息的时候携带上路由key ,根据这个路由key去交换机,去找到它所绑定的队列,然后把消息发送到对应的队列

    查看简单队列中,未绑定交换机:本质上也是使用的交换机

     默认使用的:AMQP default交换机

     (2)主题队列

    路由队列根据路由key去之指定绑定的队列,发送消息呢也要根据路由key去找到对应交换机绑定的队列,它可以满足发布与订阅模式,所有的队列绑定的同一个路由key,就相当于一条消息都可以发送到了,有一个缺点,当我们的项目越来越大,使用的路由key越来越多的时候,可能有很多个key,怎么去维护管理,下,下面就用到主题模式:

    路由key很多不利于管理吗,我们给你加通配符,类似于正则表达式

     *:表示接收一个单词

    #:表示一个或多个单词

    发送者写具体的路由key

    消费者:写通配规则的路由key

    发送者:

    1. package com.xxxx.topic.send;
    2. import com.rabbitmq.client.BuiltinExchangeType;
    3. import com.rabbitmq.client.Channel;
    4. import com.rabbitmq.client.Connection;
    5. import com.rabbitmq.client.ConnectionFactory;
    6. import java.nio.charset.StandardCharsets;
    7. /*
    8. * 主题队列:消息的生产者
    9. *
    10. * */
    11. public class Send {
    12. //定义交换机名称
    13. private final static String EXCHANGE_NAME = "exchange_topic";
    14. public static void main(String[] argv) throws Exception {
    15. // 创建连接工厂
    16. ConnectionFactory factory=new ConnectionFactory();
    17. //相关配置
    18. factory.setHost("192.168.23.129");
    19. factory.setUsername("yeb");
    20. factory.setVirtualHost("/yeb");
    21. factory.setPassword("123456");
    22. factory.setPort(5672);
    23. try(
    24. //连接工厂创建连接
    25. Connection connection=factory.newConnection();
    26. //创建信道
    27. Channel channel = connection.createChannel()){
    28. //绑定交换机
    29. channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
    30. // 消息内容
    31. String infomessage = "普通信息!";
    32. String errormessage = "错误信息!";
    33. String waringmessage = "警告信息!";
    34. //路由
    35. String infoRoutingKey="info.message.orange";
    36. String errorRoutingKey="error.rabbit.lazy";
    37. String waringRoutingKey="orange.waring.message";
    38. //发送消息 第一个参数是交换机,第二个:路由key 第三个:对应的参数 第四个:消息的实体
    39. channel.basicPublish(EXCHANGE_NAME,infoRoutingKey, null, infomessage.getBytes(StandardCharsets.UTF_8));
    40. channel.basicPublish(EXCHANGE_NAME,errorRoutingKey, null, errormessage.getBytes(StandardCharsets.UTF_8));
    41. channel.basicPublish(EXCHANGE_NAME,waringRoutingKey, null, waringmessage.getBytes(StandardCharsets.UTF_8));
    42. System.out.println(" [x] Sent '" + infomessage + "'");
    43. System.out.println(" [x] Sent '" + errormessage + "'");
    44. System.out.println(" [x] Sent '" + waringmessage + "'");
    45. }
    46. }
    47. }

    消费者1:只能匹配上面2条路由key 第一条和第三条

    1. package com.xxxx.topic.recv;
    2. import com.rabbitmq.client.*;
    3. /*
    4. * 主题队列:消息的消费者
    5. *
    6. * */
    7. public class Recv01 {
    8. //定义队列名称
    9. private final static String EXCHANGE_NAME = "exchange_topic";
    10. public static void main(String[] argv) throws Exception {
    11. // 创建连接工厂
    12. ConnectionFactory factory=new ConnectionFactory();
    13. //相关配置
    14. factory.setHost("192.168.23.129");
    15. factory.setUsername("yeb");
    16. factory.setVirtualHost("/yeb");
    17. factory.setPassword("123456");
    18. factory.setPort(5672);
    19. //连接工厂创建连接
    20. Connection connection=factory.newConnection();
    21. //创建信道
    22. Channel channel = connection.createChannel();
    23. //绑定交换机
    24. channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
    25. //获取队列(排他队列)
    26. String queueName=channel.queueDeclare().getQueue();
    27. String RoutingKey="#.message.#";//路由key,只让他接收错误信息
    28. //绑定队列和交换机、
    29. channel.queueBind(queueName,EXCHANGE_NAME,RoutingKey);
    30. System.out.println("[*] Waitint for message .To exit press CTRL+C");
    31. DeliverCallback deliverCallback=(consumerTag, delivery) -> {
    32. String message=new String(delivery.getBody(),"UTF-8");
    33. System.out.println(" [x] Received '" + message + "'");
    34. };
    35. //监听队列消费消息 第二个参数:消息自动回值告诉生产者收到消息
    36. channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {
    37. });
    38. }
    39. }

    消费者2:只能匹配第 二条

    1. package com.xxxx.topic.recv;
    2. import com.rabbitmq.client.*;
    3. /*
    4. * 主题队列:消息的消费者
    5. *
    6. * */
    7. public class Recv02 {
    8. //定义队列名称
    9. private final static String EXCHANGE_NAME = "exchange_topic";
    10. public static void main(String[] argv) throws Exception {
    11. // 创建连接工厂
    12. ConnectionFactory factory=new ConnectionFactory();
    13. //相关配置
    14. factory.setHost("192.168.23.129");
    15. factory.setUsername("yeb");
    16. factory.setVirtualHost("/yeb");
    17. factory.setPassword("123456");
    18. factory.setPort(5672);
    19. //连接工厂创建连接
    20. Connection connection=factory.newConnection();
    21. //创建信道
    22. Channel channel = connection.createChannel();
    23. //绑定交换机
    24. channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
    25. //获取队列(排他队列)
    26. String queueName=channel.queueDeclare().getQueue();
    27. String RoutingKey="*.rabbit.*";
    28. //绑定队列和交换机
    29. channel.queueBind(queueName,EXCHANGE_NAME,RoutingKey);
    30. System.out.println("[*] Waitint for message .To exit press CTRL+C");
    31. DeliverCallback deliverCallback=(consumerTag, delivery) -> {
    32. String message=new String(delivery.getBody(),"UTF-8");
    33. System.out.println(" [x] Received '" + message + "'");
    34. };
    35. //监听队列消费消息 第二个参数:消息自动回值告诉生产者收到消息
    36. channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {
    37. });
    38. }
    39. }

    启动消费者:

    多了个topic的交换机 

     路由key是带有匹配规则的路由key

     启动发送者:

    消费者1:

    消费者2:

    工作中用的最多的就是主题队列,前面讲的模式都可以使用主题队列来实现

    (3)RPC队列

    RPC本身是同步的,很少用到

    类似于发快递 reply_to:发送的目的地,correction_id:唯一表识,发送订单--给服务器订单网站给你发快递,发送到你指定的目的地,通过id判断判断是谁的,在RPC模式里不管是客户端,还是服务器,都由两种角色,生产者和消费者。

    代码略

    (4)事务

    发送者:

    1. package com.xxxx.tx.send;
    2. import com.rabbitmq.client.Channel;
    3. import com.rabbitmq.client.Connection;
    4. import com.rabbitmq.client.ConnectionFactory;
    5. import java.nio.charset.StandardCharsets;
    6. /*
    7. * 事务:消息生产者
    8. *
    9. * */
    10. public class Send {
    11. //定义队列名称
    12. private final static String QUEUE_NAME = "tx";
    13. public static void main(String[] argv) throws Exception {
    14. // 创建连接工厂
    15. ConnectionFactory factory=new ConnectionFactory();
    16. //相关配置
    17. factory.setHost("192.168.23.129");
    18. factory.setUsername("yeb");
    19. factory.setVirtualHost("/yeb");
    20. factory.setPassword("123456");
    21. factory.setPort(5672);
    22. Connection connection=null;
    23. Channel channel=null;
    24. try{
    25. //连接工厂创建连接
    26. connection=factory.newConnection();
    27. //创建信道
    28. channel = connection.createChannel();
    29. //开启事务
    30. channel.txSelect();
    31. // 绑定队列 参数第一个:队列名称 第二个:持久化 第三个:排他队列 第四个:自动删除 第五个:额外携带的参数
    32. channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    33. // 消息内容
    34. String message = "Hello World!";
    35. //发送消息 第一个参数是交换机,第三个:对应的参数 第四个:消息的实体
    36. channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
    37. //提交事务
    38. channel.txCommit();
    39. System.out.println(" [x] Sent '" + message + "'");
    40. }catch (Exception e){
    41. e.printStackTrace();
    42. //回滚事务
    43. channel.txRollback();
    44. }
    45. }
    46. }

    消费者:

    1. package com.xxxx.tx.recv;
    2. import com.rabbitmq.client.Channel;
    3. import com.rabbitmq.client.Connection;
    4. import com.rabbitmq.client.ConnectionFactory;
    5. import com.rabbitmq.client.DeliverCallback;
    6. /*
    7. * 事务:消息的消费者
    8. *
    9. * */
    10. public class Recv {
    11. //定义队列名称
    12. private final static String QUEUE_NAME = "tx";
    13. public static void main(String[] argv) throws Exception {
    14. // 创建连接工厂
    15. ConnectionFactory factory=new ConnectionFactory();
    16. //相关配置
    17. factory.setHost("192.168.23.129");
    18. factory.setUsername("yeb");
    19. factory.setVirtualHost("/yeb");
    20. factory.setPassword("123456");
    21. factory.setPort(5672);
    22. //连接工厂创建连接
    23. Connection connection=factory.newConnection();
    24. //创建信道
    25. Channel channel = connection.createChannel();
    26. //绑定队列
    27. channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    28. System.out.println("[*] Waitint for message .To exit press CTRL+C");
    29. DeliverCallback deliverCallback=(consumerTag, delivery) -> {
    30. String message=new String(delivery.getBody(),"UTF-8");
    31. System.out.println(" [x] Received '" + message + "'");
    32. };
    33. //监听队列消费消息
    34. channel.basicConsume(QUEUE_NAME,true,deliverCallback,consumerTag -> {
    35. });
    36. }
    37. }

    运行发送者,消费者:

    正常情况下接收到了消息: 

    给一个异常: 

    1. package com.xxxx.tx.send;
    2. import com.rabbitmq.client.Channel;
    3. import com.rabbitmq.client.Connection;
    4. import com.rabbitmq.client.ConnectionFactory;
    5. import java.nio.charset.StandardCharsets;
    6. /*
    7. * 事务:消息生产者
    8. *
    9. * */
    10. public class Send {
    11. //定义队列名称
    12. private final static String QUEUE_NAME = "tx";
    13. public static void main(String[] argv) throws Exception {
    14. // 创建连接工厂
    15. ConnectionFactory factory=new ConnectionFactory();
    16. //相关配置
    17. factory.setHost("192.168.23.129");
    18. factory.setUsername("yeb");
    19. factory.setVirtualHost("/yeb");
    20. factory.setPassword("123456");
    21. factory.setPort(5672);
    22. Connection connection=null;
    23. Channel channel=null;
    24. try{
    25. //连接工厂创建连接
    26. connection=factory.newConnection();
    27. //创建信道
    28. channel = connection.createChannel();
    29. //开启事务
    30. channel.txSelect();
    31. // 绑定队列 参数第一个:队列名称 第二个:持久化 第三个:排他队列 第四个:自动删除 第五个:额外携带的参数
    32. channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    33. // 消息内容
    34. String message = "Hello World!";
    35. //给一个异常
    36. int i=1/0;
    37. //发送消息 第一个参数是交换机,第三个:对应的参数 第四个:消息的实体
    38. channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
    39. //提交事务
    40. channel.txCommit();
    41. System.out.println(" [x] Sent '" + message + "'");
    42. }catch (Exception e){
    43. e.printStackTrace();
    44. //回滚事务
    45. channel.txRollback();
    46. }
    47. }
    48. }

    这样事务就进行回滚没有发送 

     很少去用事务,因为用到了事务就会降低它的性能

     (5)同步确认模式

    虽然使用事务可以解决生产者和对应的队列之间究竟能否收到消息确认这个问题,但是会降低性能,可以使用更的解决方案confirm确认模式

    确认模式最大的好处是异步的,事务是同步的会降低性能

    发送者: 

    1. package com.xxxx.confirm.sync.send;
    2. import com.rabbitmq.client.Channel;
    3. import com.rabbitmq.client.Connection;
    4. import com.rabbitmq.client.ConnectionFactory;
    5. import java.nio.charset.StandardCharsets;
    6. /*
    7. * 确认模式-同步:消息生产者
    8. *
    9. * */
    10. public class Send {
    11. //定义队列名称
    12. private final static String QUEUE_NAME = "confirm_sync";
    13. public static void main(String[] argv) throws Exception {
    14. // 创建连接工厂
    15. ConnectionFactory factory=new ConnectionFactory();
    16. //相关配置
    17. factory.setHost("192.168.23.129");
    18. factory.setUsername("yeb");
    19. factory.setVirtualHost("/yeb");
    20. factory.setPassword("123456");
    21. factory.setPort(5672);
    22. Connection connection=null;
    23. Channel channel=null;
    24. try{
    25. //连接工厂创建连接
    26. connection=factory.newConnection();
    27. //创建信道
    28. channel = connection.createChannel();
    29. //开启确认模式
    30. channel.confirmSelect();
    31. // 绑定队列 参数第一个:队列名称 第二个:持久化 第三个:排他队列 第四个:自动删除 第五个:额外携带的参数
    32. channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    33. // 消息内容
    34. String message = "Hello World!";
    35. //发送消息 第一个参数是交换机,第三个:对应的参数 第四个:消息的实体
    36. channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
    37. //普通模式单条确认模式,一条一条发送
    38. if (channel.waitForConfirms()){
    39. System.out.println("消息发送成功");
    40. }
    41. /* //批量模式confirm,只要一条没确认,直接抛异常
    42. channel.waitForConfirmsOrDie();
    43. System.out.println("消息发送成功");*/
    44. System.out.println(" [x] Sent '" + message + "'");
    45. }catch (Exception e){
    46. e.printStackTrace();
    47. }
    48. }
    49. }

     消费者:

    1. package com.xxxx.confirm.sync.recv;
    2. import com.rabbitmq.client.Channel;
    3. import com.rabbitmq.client.Connection;
    4. import com.rabbitmq.client.ConnectionFactory;
    5. import com.rabbitmq.client.DeliverCallback;
    6. /*
    7. * 确认模式-同步:消息的消费者
    8. *
    9. * */
    10. public class Recv {
    11. //定义队列名称
    12. private final static String QUEUE_NAME = "confirm_sync";
    13. public static void main(String[] argv) throws Exception {
    14. // 创建连接工厂
    15. ConnectionFactory factory=new ConnectionFactory();
    16. //相关配置
    17. factory.setHost("192.168.23.129");
    18. factory.setUsername("yeb");
    19. factory.setVirtualHost("/yeb");
    20. factory.setPassword("123456");
    21. factory.setPort(5672);
    22. //连接工厂创建连接
    23. Connection connection=factory.newConnection();
    24. //创建信道
    25. Channel channel = connection.createChannel();
    26. //绑定队列
    27. channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    28. System.out.println("[*] Waitint for message .To exit press CTRL+C");
    29. DeliverCallback deliverCallback=(consumerTag, delivery) -> {
    30. String message=new String(delivery.getBody(),"UTF-8");
    31. System.out.println(" [x] Received '" + message + "'");
    32. };
    33. //监听队列消费消息
    34. channel.basicConsume(QUEUE_NAME,true,deliverCallback,consumerTag -> {
    35. });
    36. }
    37. }

     RubbitMQ是异步的,上面的确认模式是同步的,也会降低性能,一般不会使用同步的 确认模式

    (6) 异步确认模式

    发消息,这边等确认,确认的同时也可以发消息,这个队列确认了之后返回,生产者有一个回调的方法,能够收到你返回的确认消息,进行响应的处理,所以你在等确认的同时,也可以发消息,这就叫异步 

    发送者:

    1. package com.xxxx.confirm.async.send;
    2. import com.rabbitmq.client.Channel;
    3. import com.rabbitmq.client.ConfirmListener;
    4. import com.rabbitmq.client.Connection;
    5. import com.rabbitmq.client.ConnectionFactory;
    6. import java.io.IOException;
    7. import java.nio.charset.StandardCharsets;
    8. import java.util.Collections;
    9. import java.util.SortedSet;
    10. import java.util.TreeSet;
    11. import java.util.concurrent.TimeoutException;
    12. /*
    13. * 确认模式-异步:消息生产者
    14. *
    15. * */
    16. public class Send {
    17. //定义队列名称
    18. private final static String QUEUE_NAME = "confirm_async";
    19. public static void main(String[] argv) throws Exception {
    20. // 创建连接工厂
    21. ConnectionFactory factory=new ConnectionFactory();
    22. //相关配置
    23. factory.setHost("192.168.23.129");
    24. factory.setUsername("yeb");
    25. factory.setVirtualHost("/yeb");
    26. factory.setPassword("123456");
    27. factory.setPort(5672);
    28. Connection connection=null;
    29. Channel channel=null;
    30. try{
    31. //维护信息发送回执deliveryTag
    32. final SortedSet<Long> confirmSet= Collections.synchronizedSortedSet(new TreeSet<Long>());
    33. //连接工厂创建连接
    34. connection=factory.newConnection();
    35. //创建信道
    36. channel = connection.createChannel();
    37. //开启确认模式
    38. channel.confirmSelect();
    39. // 声明队列 参数第一个:队列名称 第二个:持久化 第三个:排他队列 第四个:自动删除 第五个:额外携带的参数
    40. channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    41. //添加channel监听
    42. channel.addConfirmListener(new ConfirmListener() {
    43. //已确认
    44. @Override
    45. public void handleAck(long deliverTag, boolean mutiple) throws IOException {
    46. //mutiple=true,已确认多条 false已确认单条
    47. if (mutiple){
    48. System.out.println("handleAck--sucess-->multiple"+deliverTag);
    49. //清除前deliveryTag 项标识id
    50. confirmSet.headSet(deliverTag+1L).clear();
    51. }else {
    52. System.out.println("handleAck--sucess-->single"+deliverTag);
    53. confirmSet.remove(deliverTag);
    54. }
    55. }
    56. //没确认,可以做其他的业务处理
    57. @Override
    58. public void handleNack(long deliverTag, boolean mutiple) throws IOException {
    59. //mutiple=true未确认多条 false未确认单条
    60. if (mutiple){
    61. System.out.println("handleAck--failed-->multiple"+deliverTag);
    62. //清除前deliveryTag 项标识id
    63. confirmSet.headSet(deliverTag+1L).clear();
    64. }else {
    65. System.out.println("handleAck--failed-->single"+deliverTag);
    66. confirmSet.remove(deliverTag);
    67. }
    68. }
    69. });
    70. while(true){
    71. //创建消息
    72. String message="Hello Word";
    73. //获取unconfirm的消息序号deliverTag
    74. Long seqNo=channel.getNextPublishSeqNo();
    75. channel.basicPublish("",QUEUE_NAME,null,message.getBytes("utf-8"));
    76. //将消息的序号deliverTag添加至SortSet
    77. confirmSet.add(seqNo);
    78. }
    79. } catch (IOException | TimeoutException e){
    80. e.printStackTrace();
    81. }finally {
    82. try{
    83. //关闭通道
    84. if (null !=channel && channel.isOpen())
    85. channel.close();
    86. if (null !=connection && connection.isOpen())
    87. connection.close();
    88. }catch (TimeoutException e){
    89. e.printStackTrace();
    90. }catch (IOException e){
    91. e.printStackTrace();
    92. }
    93. }
    94. }
    95. }

     消费者:

    1. package com.xxxx.confirm.async.recv;
    2. import com.rabbitmq.client.Channel;
    3. import com.rabbitmq.client.Connection;
    4. import com.rabbitmq.client.ConnectionFactory;
    5. import com.rabbitmq.client.DeliverCallback;
    6. /*
    7. * 确认模式-异步:消息的消费者
    8. *
    9. * */
    10. public class Recv {
    11. //定义队列名称
    12. private final static String QUEUE_NAME = "confirm_async";
    13. public static void main(String[] argv) throws Exception {
    14. // 创建连接工厂
    15. ConnectionFactory factory=new ConnectionFactory();
    16. //相关配置
    17. factory.setHost("192.168.23.129");
    18. factory.setUsername("yeb");
    19. factory.setVirtualHost("/yeb");
    20. factory.setPassword("123456");
    21. factory.setPort(5672);
    22. //连接工厂创建连接
    23. Connection connection=factory.newConnection();
    24. //创建信道
    25. Channel channel = connection.createChannel();
    26. //绑定队列
    27. channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    28. System.out.println("[*] Waitint for message .To exit press CTRL+C");
    29. DeliverCallback deliverCallback=(consumerTag, delivery) -> {
    30. String message=new String(delivery.getBody(),"UTF-8");
    31. System.out.println(" [x] Received '" + message + "'");
    32. };
    33. //监听队列消费消息
    34. channel.basicConsume(QUEUE_NAME,true,deliverCallback,consumerTag -> {
    35. });
    36. }
    37. }

    运行消费者,发送者

     

    (7) SpringAMQP

    springAMQP说白了就是spring对AMQP模板的封装

     

    创建Maven项目使用模板-quickstar

    加入父依赖: 

     

    POM.XML

     

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0modelVersion>
    5. <groupId>com.xxxxgroupId>
    6. <artifactId>springamqp-demoartifactId>
    7. <packaging>pompackaging>
    8. <version>1.0-SNAPSHOTversion>
    9. <modules>
    10. <module>amqp-sendmodule>
    11. <module>amqp-recvmodule>
    12. modules>
    13. <name>springamqp-demoname>
    14. <url>http://www.example.comurl>
    15. <properties>
    16. <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    17. <maven.compiler.source>1.8maven.compiler.source>
    18. <maven.compiler.target>1.8maven.compiler.target>
    19. properties>
    20. <parent>
    21. <groupId>org.springframework.bootgroupId>
    22. <artifactId>spring-boot-starter-parentartifactId>
    23. <version>2.1.7.RELEASEversion>
    24. <relativePath/>
    25. parent>
    26. <dependencies>
    27. dependencies>
    28. project>

    删除src:

     

     

     在创建2个子项目:一个是消息的生产者,一个是消息的消费者

     子项目引入依赖:

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0</modelVersion>
    5. <artifactId>amqp-send</artifactId>
    6. <!--父项目依赖-->
    7. <parent>
    8. <groupId>com.xxxx</groupId>
    9. <artifactId>springamqp-demo</artifactId>
    10. <version>1.0-SNAPSHOT</version>
    11. </parent>
    12. <properties>
    13. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    14. <maven.compiler.source>1.8</maven.compiler.source>
    15. <maven.compiler.target>1.8</maven.compiler.target>
    16. </properties>
    17. <dependencies>
    18. <!--amqp依赖-->
    19. <dependency>
    20. <groupId>org.springframework.boot</groupId>
    21. <artifactId>spring-boot-starter-amqp</artifactId>
    22. </dependency>
    23. <!--web依赖-->
    24. <dependency>
    25. <groupId>org.springframework.boot</groupId>
    26. <artifactId>spring-boot-starter-web</artifactId>
    27. </dependency>
    28. <dependency>
    29. <groupId>org.springframework.boot</groupId>
    30. <artifactId>spring-boot-starter-test</artifactId>
    31. </dependency>
    32. </dependencies>
    33. </project>

    因为是Springboot项目,创建启动类:

    SendApplication:

    1. package com.xxxx.send;
    2. import org.springframework.boot.SpringApplication;
    3. import org.springframework.boot.autoconfigure.SpringBootApplication;
    4. @SpringBootApplication
    5. public class SendApplication {
    6. public static void main(String[] args) {
    7. SpringApplication.run(SendApplication.class,args);
    8. }
    9. }

    创建资源目录,创建application.yml配置文件:

    1. spring:
    2. rabbitmq:
    3. host: 192.168.23.129
    4. port: 5672
    5. username: yeb
    6. password: 123456
    7. virtual-host: /yeb
    8. server:
    9. port: 8081

    在创建子项目消费者:

    这个项目的依赖跟上面发送者的依赖一样

    创建springboot的启动类:

    1. package com.xxxx.recv;
    2. import org.springframework.boot.SpringApplication;
    3. import org.springframework.boot.autoconfigure.SpringBootApplication;
    4. @SpringBootApplication
    5. public class RecvApplication {
    6. public static void main(String[] args) {
    7. SpringApplication.run(RecvApplication.class,args);
    8. }
    9. }

     创建资源目录,创建配置文件:改下端口号

    1. spring:
    2. rabbitmq:
    3. host: 192.168.23.129
    4. port: 5672
    5. username: yeb
    6. password: 123456
    7. virtual-host: /yeb
    8. server:
    9. port: 8082

     

    现在要发送消息,做一些处理,这里写一个配置类

    RabbitMQConfig:

    1. package com.xxxx.send.config;
    2. import com.rabbitmq.client.AMQP;
    3. import org.springframework.amqp.core.Binding;
    4. import org.springframework.amqp.core.BindingBuilder;
    5. import org.springframework.amqp.core.Queue;
    6. import org.springframework.amqp.core.TopicExchange;
    7. import org.springframework.context.annotation.Bean;
    8. import org.springframework.context.annotation.Configuration;
    9. @Configuration
    10. public class RabbitMQConfig {
    11. //声明队列
    12. @Bean
    13. public Queue queue(){
    14. return new Queue("amqp_queue");
    15. }
    16. //声明交换机
    17. @Bean
    18. public TopicExchange topicExchange(){
    19. return new TopicExchange("amqp_exchange");
    20. }
    21. //绑定交换机和队列
    22. @Bean
    23. public Binding binding(){
    24. return BindingBuilder.bind(queue()).to(topicExchange()).with("*.amqp.#");
    25. }
    26. }

    测试类RubbitMQTest:

    发送消息:

    1. package com.xxxx.send;
    2. import org.junit.Test;
    3. import org.junit.runner.RunWith;
    4. import org.springframework.amqp.rabbit.core.RabbitTemplate;
    5. import org.springframework.beans.factory.annotation.Autowired;
    6. import org.springframework.boot.test.context.SpringBootTest;
    7. import org.springframework.test.context.junit4.SpringRunner;
    8. @SpringBootTest
    9. @RunWith(SpringRunner.class)
    10. public class RubbitMQTest {
    11. @Autowired
    12. private RabbitTemplate rabbitTemplate;
    13. @Test
    14. public void testSend(){
    15. String message="Hello";
    16. System.out.println("发送消息:"+message);
    17. //发送消息
    18. rabbitTemplate.convertAndSend("amqp_exchange","test.amqp",message);
    19. }
    20. }

    消费者:

    RecvInit:

     

    1. package com.xxxx.recv;
    2. import org.springframework.amqp.rabbit.annotation.RabbitHandler;
    3. import org.springframework.amqp.rabbit.annotation.RabbitListener;
    4. import org.springframework.boot.CommandLineRunner;
    5. import org.springframework.stereotype.Component;
    6. @Component
    7. //监听队列
    8. @RabbitListener(queues = "amqp_queue")
    9. public class RecvInit{
    10. //监听之后获取消息的处理方法
    11. @RabbitHandler
    12. public void testRecv(String message){
    13. System.out.println("接收到消息:"+message);
    14. }
    15. }

     队列中:多了amqp_queue

     当定了交换机:

    启动消费者启动类:

    已启动它就会监听:接收到消息

     

  • 相关阅读:
    产品经理需要具备哪些素质?
    java springboot 如何实现小程序支付
    8年经验面试官详解 Java 面试秘诀
    关于path用变量的问题思考
    sourcetree 配置 gitlab ssh及公钥私钥设置
    Springboot毕设项目公职备考在线学习平台e1h19(java+VUE+Mybatis+Maven+Mysql)
    外贸人必备的跨境电商常见专有名词!
    java调用c函数
    【CI/CD】Rancher CD过程--20230906
    TDengine负载均衡测试(运维场景)
  • 原文地址:https://blog.csdn.net/dengfengling999/article/details/126383511