(转) RabbitMQ学习之发布/订阅(java)

http://blog.csdn.net/zhu_tianwei/article/details/40887733

参考:http://blog.csdn.NET/lmj623565791/article/details/37657225

模拟发布订阅模式,一个消息发给多个消费者。实现一个发送日志,一个接收者将接收到的数据写到硬盘上,与此同时,另一个接收者把接收到的消息展现在屏幕上。

转发器类型使用:fanout。fanout类型转发器特别简单,把所有它介绍到的消息,广播到所有它所知道的队列。

channel.exchangeDeclare("logs","fanout");

1.发送日志SendLog.Java

[java] view plain copy
 
 print?
  1. package cn.slimsmart.rabbitmq.demo.fanout;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import com.rabbitmq.client.AMQP;  
  6. import com.rabbitmq.client.Channel;  
  7. import com.rabbitmq.client.Connection;  
  8. import com.rabbitmq.client.ConnectionFactory;  
  9.   
  10. public class SendLog {  
  11.     // 转发器  
  12.     private final static String EXCHANGE_NAME = "ex_log";  
  13.   
  14.     @SuppressWarnings("deprecation")  
  15.     public static void main(String[] args) throws Exception {  
  16.         // 创建连接和频道  
  17.         ConnectionFactory factory = new ConnectionFactory();  
  18.         factory.setHost("192.168.101.174");  
  19.         // 指定用户 密码  
  20.         factory.setUsername("admin");  
  21.         factory.setPassword("admin");  
  22.         // 指定端口  
  23.         factory.setPort(AMQP.PROTOCOL.PORT);  
  24.         Connection connection = factory.newConnection();  
  25.         Channel channel = connection.createChannel();  
  26.         /** 
  27.          * 声明转发器和类型 可用的转发器类型Direct Topic Headers Fanout 参考:http://melin.iteye.com/blog/691265 
  28.          * Direct Exchange – 处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。 
  29.          * Fanout Exchange – 不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。 
  30.          * 很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。  
  31.          * Topic Exchange – 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。 
  32.          * 因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.*” 只会匹配到“audit.irs”。 
  33.          */  
  34.         channel.exchangeDeclare(EXCHANGE_NAME, "fanout");  
  35.   
  36.         String message = new Date().toLocaleString() + " : log something";  
  37.         // 指定消息发送到的转发器  
  38.         channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());  
  39.   
  40.         System.out.println(" [x] Sent '" + message + "'");  
  41.   
  42.         channel.close();  
  43.         connection.close();  
  44.     }  
  45.   
  46. }  
2.接受写文件类代码ReceiveLogsToFile.java

创建一个队列,然后将队列与转发器绑定,然后将消费者与该队列绑定,然后写入日志文件。

[java] view plain copy
 
 print?
  1. package cn.slimsmart.rabbitmq.demo.fanout;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileNotFoundException;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.text.SimpleDateFormat;  
  8. import java.util.Date;  
  9.   
  10. import com.rabbitmq.client.AMQP;  
  11. import com.rabbitmq.client.Channel;  
  12. import com.rabbitmq.client.Connection;  
  13. import com.rabbitmq.client.ConnectionFactory;  
  14. import com.rabbitmq.client.QueueingConsumer;  
  15.   
  16. public class ReceiveLogsToFile {  
  17.   
  18.     private final static String EXCHANGE_NAME = "ex_log";  
  19.   
  20.     public static void main(String[] args) throws Exception {  
  21.         // 创建连接和频道  
  22.         ConnectionFactory factory = new ConnectionFactory();  
  23.         factory.setHost("192.168.101.174");  
  24.         // 指定用户 密码  
  25.         factory.setUsername("admin");  
  26.         factory.setPassword("admin");  
  27.         // 指定端口  
  28.         factory.setPort(AMQP.PROTOCOL.PORT);  
  29.         Connection connection = factory.newConnection();  
  30.         Channel channel = connection.createChannel();  
  31.         /** 
  32.          * 声明转发器和类型 可用的转发器类型Direct Topic Headers Fanout 
  33.          * Direct Exchange – 处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。 
  34.          * Fanout Exchange – 不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。 
  35.          * 很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。  
  36.          * Topic Exchange – 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。 
  37.          * 因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.*” 只会匹配到“audit.irs”。 
  38.          */  
  39.         channel.exchangeDeclare(EXCHANGE_NAME, "fanout");  
  40.         //创建一个非持久的、唯一的且自动删除的队列且队列名称由服务器随机产生一般情况这个名称与amq.gen-JzTY20BRgKO-HjmUJj0wLg 类似。  
  41.         String queueName = channel.queueDeclare().getQueue();  
  42.         // 为转发器指定队列,设置binding  
  43.         channel.queueBind(queueName, EXCHANGE_NAME, "");  
  44.   
  45.         System.out.println(" [*] Waiting for messages. To exit press CTRL+C");  
  46.   
  47.         QueueingConsumer consumer = new QueueingConsumer(channel);  
  48.         // 指定接收者,第二个参数为自动应答,无需手动应答  
  49.         channel.basicConsume(queueName, true, consumer);  
  50.   
  51.         while (true) {  
  52.             QueueingConsumer.Delivery delivery = consumer.nextDelivery();  
  53.             String message = new String(delivery.getBody());  
  54.   
  55.             print2File(message);  
  56.         }  
  57.     }  
  58.   
  59.     private static void print2File(String msg) {  
  60.         try {  
  61.             String dir = ReceiveLogsToFile.class.getClassLoader().getResource("").getPath();  
  62.             String logFileName = new SimpleDateFormat("yyyy-MM-dd").format(new Date());  
  63.             File file = new File(dir, logFileName + ".txt");  
  64.             FileOutputStream fos = new FileOutputStream(file, true);  
  65.             fos.write((msg + " ").getBytes());  
  66.             fos.flush();  
  67.             fos.close();  
  68.         } catch (FileNotFoundException e) {  
  69.             e.printStackTrace();  
  70.         } catch (IOException e) {  
  71.             e.printStackTrace();  
  72.         }  
  73.     }  
  74. }  


3.接受写控制台代码ReceiveLogsToConsole.java

创建一个队列,然后将队列与转发器绑定,然后将消费者与该队列绑定,然后打印到控制台。

[java] view plain copy
 
 print?
  1. package cn.slimsmart.rabbitmq.demo.fanout;  
  2.   
  3. import com.rabbitmq.client.AMQP;  
  4. import com.rabbitmq.client.Channel;  
  5. import com.rabbitmq.client.Connection;  
  6. import com.rabbitmq.client.ConnectionFactory;  
  7. import com.rabbitmq.client.QueueingConsumer;  
  8.   
  9. public class ReceiveLogsToConsole {  
  10.     private final static String EXCHANGE_NAME = "ex_log";    
  11.     public static void main(String[] args) throws Exception {  
  12.         // 创建连接和频道    
  13.         ConnectionFactory factory = new ConnectionFactory();    
  14.         factory.setHost("192.168.101.174");  
  15.         // 指定用户 密码  
  16.         factory.setUsername("admin");  
  17.         factory.setPassword("admin");  
  18.         // 指定端口  
  19.         factory.setPort(AMQP.PROTOCOL.PORT);  
  20.         Connection connection = factory.newConnection();    
  21.         Channel channel = connection.createChannel();    
  22.     
  23.         channel.exchangeDeclare(EXCHANGE_NAME, "fanout");    
  24.         // 创建一个非持久的、唯一的且自动删除的队列且队列名称由服务器随机产生一般情况这个名称与amq.gen-JzTY20BRgKO-HjmUJj0wLg 类似。  
  25.         String queueName = channel.queueDeclare().getQueue();    
  26.         // 为转发器指定队列,设置binding    
  27.         channel.queueBind(queueName, EXCHANGE_NAME, "");    
  28.     
  29.         System.out.println(" [*] Waiting for messages. To exit press CTRL+C");    
  30.     
  31.         QueueingConsumer consumer = new QueueingConsumer(channel);    
  32.         // 指定接收者,第二个参数为自动应答,无需手动应答    
  33.         channel.basicConsume(queueName, true, consumer);    
  34.     
  35.         while (true)    
  36.         {    
  37.             QueueingConsumer.Delivery delivery = consumer.nextDelivery();    
  38.             String message = new String(delivery.getBody());    
  39.             System.out.println(" [x] Received '" + message + "'");    
  40.     
  41.         }    
  42.     }  
  43.   
  44. }  


先启动2个消费者,再运行生产者观察消费者运行情况,可见2个消费者都受到相同的消息。生产者将消息发送至转发器,转发器决定将消息发送至哪些队列,消费者绑定队列获取消息。

原文地址:https://www.cnblogs.com/telwanggs/p/7124593.html