rabbitmq消息队列的简单入门

一rabbitmq
rabbitmq降低主程序线程压力,是一种非阻塞模式的分布式消息队列服务器,有生产者生产到rabbitmq,消费者消费

二。rabbitmq安装

1.安装rabbitmq

安装过程 参考 (http://www.rabbitmq.com/install-rpm.html)
rabbitmq-server 目前安装包被包含在 Fedora rpm仓库中 Fedora是epel库

yum -y install epel-release.noarch  

查看是否存在rabbitmq 然后安装

yum search rabbitmq-server  
yum -y install rabbitmq-server  

查看安装包

tail -1000 /var/log/yum.log  

查看rabbitmq-server被安装的所有文件的位置

/etc/logrotate.d/rabbitmq-server  
/etc/rabbitmq  
/etc/rabbitmq/rabbitmq.config  
/usr/lib/ocf/resource.d/rabbitmq/rabbitmq-server  
/usr/lib/rabbitmq/bin  
/usr/lib/rabbitmq/bin/rabbitmq-defaults  
/usr/lib/rabbitmq/bin/rabbitmq-env  
/usr/lib/rabbitmq/bin/rabbitmq-plugins  
/usr/lib/rabbitmq/bin/rabbitmq-server  
/usr/lib/rabbitmq/bin/rabbitmqctl  

查看rabbitmq-server所有的参考文档

[root@node3 log]# rpm -qd rabbitmq-server-3.3.5-34.el7.noarch  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-APACHE2-ExplorerCanvas  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-APL2-Stomp-Websocket  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-Apache-Basho  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-BSD-base64js  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-BSD-glMatrix  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-EJS10  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-Flot  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-Mochi  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-Sammy060  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-eldap  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MIT-jQuery164  
/usr/share/doc/rabbitmq-server-3.3.5/LICENSE-MPL-RabbitMQ  
/usr/share/doc/rabbitmq-server-3.3.5/rabbitmq.config.example  
/usr/share/man/man1/rabbitmq-plugins.1.gz  
/usr/share/man/man1/rabbitmq-server.1.gz  
/usr/share/man/man1/rabbitmqctl.1.gz  
/usr/share/man/man5/rabbitmq-env.conf.5.gz  

其中比较重要的两个参考文件(这两个只是参考)
运行配置文件:rabbitmq.config.example
环境配置文件:/usr/share/man/man5/rabbitmq-env.conf.5.gz
默认该两文件需要配置在 /etc/rabbitmq目录下 默认只有一个

[root@node3 log]# cd /etc/rabbitmq && ll  
total 20  
-rw-r--r-- 1 root root 18555 Aug 11  2014 rabbitmq.config  

单机默认配置足够 具体配置参考官网 (http://www.rabbitmq.com/configure.html)
rabbitmq默认安装后 会添加账号rabbitmq 默认以该账号运行

[root@node3 rabbitmq]# more /etc/passwd | grep rabbitmq  
rabbitmq:x:992:990:RabbitMQ messaging server:/var/lib/rabbitmq:/sbin/nologin  

2》启动rabbitmq

扫描二维码关注公众号,回复: 8990959 查看本文章

启动后 查看默认的端口 5672

[root@node3 rabbitmq]# netstat -aon | grep 5672  
tcp        0      0 0.0.0.0:25672           0.0.0.0:*               LISTEN      off (0.00/0/0)  
tcp6       0      0 :::5672                 :::*                    LISTEN      off (0.00/0/0) 

关闭和查看rabiitmq的状态可以使用命令

[root@node3 system]# rabbitmqctl stop  
Stopping and halting node rabbit@node3 ...  
...done.  

rabbitmq默认提供了一个web管理工具(rabbitmq_management)参考官方http://www.rabbitmq.com/management.html 默认已经安装 是一个插件

查看所有插件

[root@bogon bin]# ./rabbitmq-plugins list
[ ] amqp_client                       3.1.5
[ ] cowboy                            0.5.0-rmq3.1.5-git4b93c2d
[ ] eldap                             3.1.5-gite309de4
[ ] mochiweb                          2.7.0-rmq3.1.5-git680dba8
[ ] rabbitmq_amqp1_0                  3.1.5
[ ] rabbitmq_auth_backend_ldap        3.1.5
[ ] rabbitmq_auth_mechanism_ssl       3.1.5
[ ] rabbitmq_consistent_hash_exchange 3.1.5
[ ] rabbitmq_federation               3.1.5
[ ] rabbitmq_federation_management    3.1.5
[ ] rabbitmq_jsonrpc                  3.1.5
[ ] rabbitmq_jsonrpc_channel          3.1.5
[ ] rabbitmq_jsonrpc_channel_examples 3.1.5
[ ] rabbitmq_management               3.1.5
[ ] rabbitmq_management_agent         3.1.5
[ ] rabbitmq_management_visualiser    3.1.5
[ ] rabbitmq_mqtt                     3.1.5
[ ] rabbitmq_shovel                   3.1.5
[ ] rabbitmq_shovel_management        3.1.5
[ ] rabbitmq_stomp                    3.1.5
[ ] rabbitmq_tracing                  3.1.5
[ ] rabbitmq_web_dispatch             3.1.5
[ ] rabbitmq_web_stomp                3.1.5
[ ] rabbitmq_web_stomp_examples       3.1.5
[ ] rfc4627_jsonrpc                   3.1.5-git5e67120
[ ] sockjs                            0.3.4-rmq3.1.5-git3132eb9
[ ] webmachine                        1.10.3-rmq3.1.5-gite9359c7

启用该插件即可

[root@bogon ~]# cd /usr/lib/rabbitmq/bin
[root@bogon bin]# ./rabbitmq-plugins enable rabbitmq_management
重启rabbitmq-server
[root@bogon bin]# service rabbitmq-server restart
Restarting rabbitmq-server: RabbitMQ is not running
SUCCESS
rabbitmq-server.
浏览器访问(开启了端口 15672 当前机器ip是126.128) (http://192.168.126.128:15672/)
输入用户名 guest和guest

以后我们用Java代码去掉就是调用5672 这个端口。我们重点关注的是Queues和Exchanges

三.rabbitmq的api的调用

参考官方文档 http://www.rabbitmq.com/getstarted.html

rabbitmq 官方操作api提供了n多种语言 前面几种都会 java是本职 所以使用java

rabbitmq支持6种消息接受和转发机制

1.简单模式(http://www.rabbitmq.com/tutorials/tutorial-one-java.html)

1 个生产者对应一个消费者每个队列都有一个唯一名字。一个生产者推送消息到队列,单个消费者消费消息

简单的调用,创建本地生产者maven文件 在pom.xml中添加rabbitmq的架包

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cn.et</groupId>
  <artifactId>Rabbitmq_Pub</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  	<dependencies>
  		<!-- 添加rabbitmq的架包 -->
  		<dependency>
  			<groupId>com.rabbitmq</groupId>  
          	<artifactId>amqp-client</artifactId>  
          	<version>4.2.0</version>  
  		</dependency>
  	</dependencies>
</project>

创建main方法

package cn.et;
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;
 
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
//生产者推送消息到队列
public class PubEmail {
	//将对象序列化为字节数组
	public static byte[] ser(Object obj) throws IOException{
		//接收被写入的字节数组
		ByteArrayOutputStream bos= new ByteArrayOutputStream();
		//把对象序列化成字节数组
		ObjectOutputStream oos= new ObjectOutputStream(bos);
		//写入
		oos.writeObject(obj);
		return bos.toByteArray();
	}
	//反序列化
	public static Object dser(byte[] src) throws Exception{
		//从字节数组读取数据
		ByteArrayInputStream bis = new ByteArrayInputStream(src);
		//把字节数组反序列化成对象
		ObjectInputStream ois= new ObjectInputStream(bis);
		return ois.readObject();	
	}
	
	//任务被发送的队列名称
	static String QUEUE_NAME="MAILQueue";
	public static void main(String[] args) throws Exception {
		//模拟一个任务消息,以发邮件为例
		Map map = new HashMap();
		//接收邮件的邮箱
		map.put("sendto", "");
		//邮件标题
		map.put("subject", "测试邮件");
		//邮件内容
		map.put("content", "注册成功你的验证码是135469");
		//连接远程rabbit-server服务器  
        ConnectionFactory factory = new ConnectionFactory();  
        //本机LinuxIP
        factory.setHost("192.168.126.128");  
        factory.setPort(5672);  
        Connection connection = factory.newConnection();  
        Channel channel = connection.createChannel();  
        //定义创建一个队列  
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);  
        //发送消息  
        channel.basicPublish("", QUEUE_NAME, null, ser(map)); //注意发送和接受段相同字符集否则出现乱码  
        channel.close();  
        connection.close();  
	}
}

创建消费者maven项目,在pom.xml配置rabbitmq

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cn.et</groupId>
  <artifactId>Rabbitmq_Cons</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  	 <!--  依赖springboot -->
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.9.RELEASE</version>
</parent>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Dalston.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
  <dependencies>
  <!-- springboot每一个框架的集成都是一个starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  	<!-- 配置发送邮箱 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
  <!-- 添加rabbitmq的架包 -->
  		<dependency>
  			<groupId>com.rabbitmq</groupId>  
          	<artifactId>amqp-client</artifactId>  
          	<version>4.2.0</version>  
  		</dependency>  
</dependencies>
</project>

创建消费者消费的类

package cn.et;
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
 
//消费者从队列消费
@RestController
public class Mail_Cons {
	//装配发送邮件的类
	@Autowired
	JavaMailSender jms;
	//将对象序列化为字节数组
		public static byte[] ser(Object obj) throws IOException{
			//接收被写入的字节数组
			ByteArrayOutputStream bos= new ByteArrayOutputStream();
			//把对象序列化成字节数组
			ObjectOutputStream oos= new ObjectOutputStream(bos);
			//写入
			oos.writeObject(obj);
			return bos.toByteArray();
		}
		//反序列化
		public static Object dser(byte[] src) throws Exception{
			//从字节数组读取数据
			ByteArrayInputStream bis = new ByteArrayInputStream(src);
			//把字节数组反序列化成对象
			ObjectInputStream ois= new ObjectInputStream(bis);
			return ois.readObject();	
		}
		//消费者消费的队列名称
	private static String QUEUE_NAME="MAILQueue";
	@GetMapping("/sends")
	public void asyncRec() throws Exception {
		
		 ConnectionFactory factory = new ConnectionFactory();  
	        factory.setHost("192.168.126.128");  
	        Connection connection = factory.newConnection();  
	        Channel channel = connection.createChannel();  
	        //消费者也需要定义队列 有可能消费者先于生产者启动   
	        channel.queueDeclare(QUEUE_NAME, false, false, false, null);  
	        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");  
	        //定义回调抓取消息  
	        Consumer consumer = new DefaultConsumer(channel) {  
	            @Override  
	            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,  
	                    byte[] body) throws IOException {  
	            	try {
						Map map=(Map) dser(body);
						SimpleMailMessage smm= new SimpleMailMessage();
						//设置发送方
						smm.setFrom("[email protected]");
						//设置收件方
						smm.setTo(map.get("sendto").toString());
						//设置邮件标题
						smm.setSubject(map.get("subject").toString());
						//设置邮件内容
						smm.setText(map.get("content").toString());
						jms.send(smm);
					} catch (Exception e) {
						e.printStackTrace();
					}
	            }  
	        };  
	        channel.basicConsume(QUEUE_NAME, true, consumer);  
	}
}

配置发送邮件的配置文件在src/main/resources中创建application.properties

#配置smtp的主机名
spring.mail.host=smtp.126.com
#配置发送方的邮件名
[email protected]
#配置发送方的授权密码
spring.mail.password=zmw960221
#配置stm端口
spring.mail.port=25
spring.mail.protocol=smtp

创建main方法运行

package cn.et;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Main {
	public static void main(String[] args) {
		SpringApplication.run(Main.class, args);
	}
}

在浏览器中输入消费者的路径localhost:8080/sends

2.工作队列模式(http://www.rabbitmq.com/tutorials/tutorial-two-java.html)

工作队列一般用于任务分配 发布者发布任务到队列 多个消息接收者 接收消息 谁接收到某个消息 其他接收者就只能消费其他消息 队列中的一个消息只能被一个接收者消费(类似12306抢票一样 比如某个车次 就相当于队列 该车次 出来一些座位票 一张票只能被一个人抢到 最终 所有的座位票都被不同的人抢到 注意: 一个人可以抢多张票)

简单的调用,创建生产者类

package cn.et.two;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class PubEmailTwo {
	
	//任务被发送的队列名称
	static String QUEUE_NAME="WorkQueue";
	public static void main(String[] args) throws Exception {
	
		//连接远程rabbit-server服务器  
        ConnectionFactory factory = new ConnectionFactory();  
        //本机LinuxIP
        factory.setHost("192.168.126.128");  
        factory.setPort(5672);  
        Connection connection = factory.newConnection();  
        Channel channel = connection.createChannel();  
        //定义创建一个队列  
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);  
        //发送消息  
        for(int i=0;i<10;i++){
        	channel.basicPublish("", QUEUE_NAME, null, ("这是:"+i).getBytes("UTF-8")); //注意发送和接受段相同字符集否则出现乱码  
        }
        System.out.println("生产者生产");
        channel.close();  
        connection.close();  
	}
}

运行生产者
SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
生产者生产

创建消费者

package cn.et.two;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
 
//消费者从队列消费
public class Mail_ConsTwo {
	
	private static String QUEUE_NAME="WorkQueue";
	
	public static void main(String[] args) throws Exception {
		
		 ConnectionFactory factory = new ConnectionFactory();  
	        factory.setHost("192.168.126.128");  
	        Connection connection = factory.newConnection();  
	        Channel channel = connection.createChannel();  
	        //消费者也需要定义队列 有可能消费者先于生产者启动   
	        channel.queueDeclare(QUEUE_NAME, false, false, false, null);  
	        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");  
	        //定义回调抓取消息  
	        Consumer consumer = new DefaultConsumer(channel) {  
	            @Override  
	            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,  
	                    byte[] body) throws IOException {  
	            	System.out.println(new String(body,"UTF-8"));
	            }  
	        };  
	        channel.basicConsume(QUEUE_NAME, true, consumer);  
	}
}

运行2次消费者

[] Waiting for messages. To exit press CTRL+C
这是:1
这是:3
这是:5
这是:7
这是:9
[
] Waiting for messages. To exit press CTRL+C
这是:0
这是:2
这是:4
这是:6
这是:8

3》发布订阅模式(http://www.rabbitmq.com/tutorials/tutorial-three-java.html)

生产者发布主题消息 订阅者订阅该主题 订阅该主题的所有订阅者都可以接受消息 (类似于广播 广播有个频道(主题) 听广播的用户就是订阅者广播中推送的新闻和内容就是消息)
发布订阅模式 引入了交换器的概念 消息发布者发布消息到交换器 订阅者定义一个队列(每个订阅者定义一个)用于接受消息 交换器 起到了中转消息的作用 这里面还有个routingkey 如果定义了routingkey 交换器只会将消息发给自己的routingkey和订阅者队列绑定routringkey和相同或者相似的队列比如交换器定义routingkey是 abc 订阅者将自己队列绑定到交换器时指定routingkey是abc 交换器发现routingkey相同所以消息被发送到这个队列

这里 因为所有的订阅者需要获取消息 所以routingkey为空 订阅者产生的队列名称应该为随机字符串就可
交换器 有以下几种类型 direct, topic, headers and fanout
发布订阅模式 应该使用fanout(广播)

创建生产者

package cn.et.three;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
public class PubEmailThree {
	
	/**  
     * 交换器名称  
     */  
    private static final String EXCHANGE_NAME = "db.logs";  
    public static void main(String[] args) throws Exception {  
        //连接远程rabbit-server服务器  
        ConnectionFactory factory = new ConnectionFactory();  
        factory.setHost("192.168.126.128");  
        factory.setPort(5672);  
        Connection connection = factory.newConnection();  
        Channel channel = connection.createChannel();  
        //定义创建一个交换器 参数1 名称  参数2 交换器类型 参数3表示将交换器信息永久保存在服务器磁盘上 关闭rabbitmqserver也不会丢失  
       //fanout发布订阅模式
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout",true);  
        String message = null;  
        //同时发送10条消息  
        for(int i=0;i<10;i++){  
            message="发送第"+i+"消息";  
            //第二个参数就是routingkey  不填 默认会转发给所有的订阅者队列  
            channel.basicPublish(EXCHANGE_NAME, "", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("UTF-8"));  
        }  
          
        System.out.println(" [x] Sent 6 message");  
        channel.close();  
        connection.close();  
    }
}

创建消费者

package cn.et.three;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
 
//消费者从队列消费
public class Mail_ConsThree {
	
	/**  
     * 交换器名称  
     */  
    private static final String EXCHANGE_NAME = "db.logs";  
	public static void main(String[] args) throws Exception {
		
		 ConnectionFactory factory = new ConnectionFactory();  
	        factory.setHost("192.168.126.128");  
	        Connection connection = factory.newConnection();  
	        Channel channel = connection.createChannel();  
	        //消费者也需要定义队列 有可能消费者先于生产者启动   
	        channel.exchangeDeclare(EXCHANGE_NAME, "fanout",true);  
	      //  channel.basicQos(1);  
	        //产生一个随机的队列 该队列用于从交换器获取消息  
	        String queueName = channel.queueDeclare().getQueue();  
	        //将队列和某个交换器绑定 就可以正式获取消息了 routingkey和交换器的一样都设置成空  
	        channel.queueBind(queueName, EXCHANGE_NAME, "");  
	        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");  
	        //定义回调抓取消息  
	        Consumer consumer = new DefaultConsumer(channel) {   
	            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,  
	                    byte[] body) throws IOException {  
	                String message = new String(body, "UTF-8");  
	                System.out.println(" [x] Received '" + message + "'");  
	                //参数2 true表示确认该队列所有消息  false只确认当前消息 每个消息都有一个消息标记  
	                 
	            }  
	        };  
	        //参数2 表示手动确认  
	        channel.basicConsume(queueName, true, consumer);   
	}
}

先运行两次生产者,创建队列
[] Waiting for messages. To exit press CTRL+C
[
] Waiting for messages. To exit press CTRL+C

运行生产者

SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
[x] Sent 6 message

消费者消费

[] Waiting for messages. To exit press CTRL+C
[x] Received ‘发送第0消息’
[x] Received ‘发送第1消息’
[x] Received ‘发送第2消息’
[x] Received ‘发送第3消息’
[x] Received ‘发送第4消息’
[x] Received ‘发送第5消息’
[x] Received ‘发送第6消息’
[x] Received ‘发送第7消息’
[x] Received ‘发送第8消息’
[x] Received ‘发送第9消息’
[
] Waiting for messages. To exit press CTRL+C
[x] Received ‘发送第0消息’
[x] Received ‘发送第1消息’
[x] Received ‘发送第2消息’
[x] Received ‘发送第3消息’
[x] Received ‘发送第4消息’
[x] Received ‘发送第5消息’
[x] Received ‘发送第6消息’
[x] Received ‘发送第7消息’
[x] Received ‘发送第8消息’
[x] Received ‘发送第9消息’

4》路由模式(http://www.rabbitmq.com/tutorials/tutorial-three-java.html)

前面第三种发布订阅模式 每个订阅者都会收到交换器发出的消息 因为发布者发布消息的routingkey是空 订阅者接受消息队列的routingkey也是空 发布者发布的消息 所有的订阅者都能接收到 路由模式表示 发布者发布的消息的routingkey和订阅者接受消息队列的routingkey都不为空 相同的则可以接受消息 比如发送日志的例子
该种模式 交换器的类型 必须是direct 而不是之前的faout 比如 发布者P 发布的多个消息 使用的多个routingkey 比如error info warning等比如一条错误消息 routingkey定义为 error 警告消息是warning 如果某个订阅者的临时队列使用的routingkey是error 将接受到error消息是warning将接受到警告消息 其他消息如果没有队列绑定routingkey 将被丢弃模拟上图的例子 比如有四类消息 C1订阅者程序 绑定到交换机X routingkey是error 出现error写入到磁盘 C2订阅者程序绑定到交换机X routingkey绑定三个 info error warning 接受到消息只是打印

创建生产者

package cn.et.four;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
public class PubEmailFour {
	
	/**  
     * 交换器名称  
     */  
    private static final String EXCHANGE_NAME = "db.ye";  
    public static void main(String[] args) throws Exception {  
    	  //连接远程rabbit-server服务器  
        ConnectionFactory factory = new ConnectionFactory();  
        factory.setHost("192.168.126.128");  
        factory.setPort(5672);  
        Connection connection = factory.newConnection();  
        Channel channel = connection.createChannel();  
        //定义创建一个交换器 参数1 名称  参数2 交换器类型 参数3表示将交换器信息永久保存在服务器磁盘上 关闭rabbitmqserver也不会丢失  
        //路由模式 direct
        channel.exchangeDeclare(EXCHANGE_NAME, "direct",true);  
        //第二个参数就是routingkey     
        channel.basicPublish(EXCHANGE_NAME, "error", MessageProperties.PERSISTENT_TEXT_PLAIN, "这是错误信息".getBytes("UTF-8"));  
        channel.basicPublish(EXCHANGE_NAME, "info", MessageProperties.PERSISTENT_TEXT_PLAIN, "这是程序运行信息".getBytes("UTF-8"));  
        channel.basicPublish(EXCHANGE_NAME, "warning", MessageProperties.PERSISTENT_TEXT_PLAIN, "这是警告".getBytes("UTF-8"));  
          System.out.println("[X] sent 6 message");
        channel.close();  
        connection.close();  
    }  
    
}

创建消费者

package cn.et.four;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
 
//消费者从队列消费
public class Mail_ConsFour {
	
	/**  
     * 交换器名称  
     */  
    private static final String EXCHANGE_NAME = "db.ye";  
	public static void main(String[] args) throws Exception {
		 //连接远程rabbit-server服务器 
		 ConnectionFactory factory = new ConnectionFactory();  
	        factory.setHost("192.168.126.128");  
	        Connection connection = factory.newConnection();  
	        Channel channel = connection.createChannel();  
	        //消费者也需要定义队列 有可能消费者先于生产者启动   
	        channel.exchangeDeclare(EXCHANGE_NAME, "direct",true);  
	      //  channel.basicQos(1);  
	        //产生一个随机的队列 该队列用于从交换器获取消息  
	        String queueName = channel.queueDeclare().getQueue();  
	        //将队列和某个交换器绑定 设置key就可以正式获取消息了 
	        channel.queueBind(queueName, EXCHANGE_NAME, "info");  
	        System.out.println(" [*] Waiting for messages. To exit press CTRL+V");  
	        //定义回调抓取消息  
	        Consumer consumer = new DefaultConsumer(channel) {   
	            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,  
	                    byte[] body) throws IOException {  
	                String message = new String(body, "UTF-8");  
	                System.out.println(" [x] Received '" + message + "'");  
	                //参数2 true表示确认该队列所有消息  false只确认当前消息 每个消息都有一个消息标记  
	                 
	            }  
	        };  
	        //参数2 表示手动确认  
	        channel.basicConsume(queueName, true, consumer);   
	}
}

先运行三次消费者,每次运行确保key的不同
channel.queueBind(queueName, EXCHANGE_NAME, “info”||“warning”||“error”);
在运行生产者

SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
[X] sent 6 message
消费者
[] Waiting for messages. To exit press CTRL+V
[x] Received ‘这是警告’
[
] Waiting for messages. To exit press CTRL+V
[x] Received ‘这是错误信息’
[*] Waiting for messages. To exit press CTRL+V
[x] Received ‘这是程序运行信息’

5》Topics路由模式(http://www.rabbitmq.com/tutorials/tutorial-three-java.html)
该种模式和路由模式类似 只是消息的routingkey 是通过.隔开的多个字符组成 订阅者的消息队列绑定的routingkey可以使用通配符通配所有满足条件的交换机消息 匹配上则接收消息 这种类型的消息 使用的交换器类型是 topic

接收者接收消息可以设置routingkey为表达式模糊匹配 *匹配一个单词 #匹配多个

以发布日记为例
创建发布者

package cn.et.five;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
public class PubEmailFive {
	
	/**  
     * 交换器名称  
     */  
    private static final String EXCHANGE_NAME = "db.ge";  
    public static void main(String[] args) throws Exception {  
    	  //连接远程rabbit-server服务器  
        ConnectionFactory factory = new ConnectionFactory();  
        factory.setHost("192.168.126.128");  
        factory.setPort(5672);  
        Connection connection = factory.newConnection();  
        Channel channel = connection.createChannel();  
        //定义创建一个交换器 参数1 名称  参数2 交换器类型 参数3表示将交换器信息永久保存在服务器磁盘上 关闭rabbitmqserver也不会丢失  
        //路由模式 direct
        channel.exchangeDeclare(EXCHANGE_NAME, "topic",true);  
        //第二个参数就是routingkey     
        channel.basicPublish(EXCHANGE_NAME, "d.error", MessageProperties.PERSISTENT_TEXT_PLAIN, "这是错误信息".getBytes("UTF-8"));  
        channel.basicPublish(EXCHANGE_NAME, "d.info", MessageProperties.PERSISTENT_TEXT_PLAIN, "这是程序运行信息".getBytes("UTF-8"));  
        channel.basicPublish(EXCHANGE_NAME, "d.warning", MessageProperties.PERSISTENT_TEXT_PLAIN, "这是警告".getBytes("UTF-8"));
        channel.basicPublish(EXCHANGE_NAME, "a.c.error", MessageProperties.PERSISTENT_TEXT_PLAIN, "zs这是错误信息".getBytes("UTF-8"));  
        channel.basicPublish(EXCHANGE_NAME, "a.c.info", MessageProperties.PERSISTENT_TEXT_PLAIN, "ls这是程序运行信息".getBytes("UTF-8"));  
        channel.basicPublish(EXCHANGE_NAME, "a.c.warning", MessageProperties.PERSISTENT_TEXT_PLAIN, "ww这是警告".getBytes("UTF-8"));  
          System.out.println("[X] sent 6 message");
        channel.close();  
        connection.close();  
    }  
    
}

创建生产者

package cn.et.five;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
 
//消费者从队列消费
public class Mail_ConsFive {
	
	/**  
     * 交换器名称  
     */  
    private static final String EXCHANGE_NAME = "db.ge";  
	public static void main(String[] args) throws Exception {
		 //连接远程rabbit-server服务器 
		 ConnectionFactory factory = new ConnectionFactory();  
	        factory.setHost("192.168.126.128");  
	        Connection connection = factory.newConnection();  
	        Channel channel = connection.createChannel();  
	        //消费者也需要定义队列 有可能消费者先于生产者启动   
	        channel.exchangeDeclare(EXCHANGE_NAME, "topic",true);  
	      //  channel.basicQos(1);  
	        //产生一个随机的队列 该队列用于从交换器获取消息  
	        String queueName = channel.queueDeclare().getQueue();  
	        //将队列和某个交换器绑定 就可以正式获取消息了 
	         channel.queueBind(queueName, EXCHANGE_NAME, "d.*");  
	        System.out.println(" [*] Waiting for messages. To exit press CTRL+V");  
	        //定义回调抓取消息  
	        Consumer consumer = new DefaultConsumer(channel) {   
	            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,  
	                    byte[] body) throws IOException {  
	                String message = new String(body, "UTF-8");  
	                System.out.println(" [x] Received '" + message + "'");  
	                //参数2 true表示确认该队列所有消息  false只确认当前消息 每个消息都有一个消息标记  
	                 
	            }  
	        };  
	        //参数2 表示手动确认  
	        channel.basicConsume(queueName, true, consumer);   
	}
}

先运行消费者,在把 channel.queueBind(queueName, EXCHANGE_NAME, “d.*”); d.*改为a.#在运行

[] Waiting for messages. To exit press CTRL+V
在运行生产者
SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
[X] sent 6 message
生产者
[
] Waiting for messages. To exit press CTRL+V
[x] Received ‘这是错误信息’
[x] Received ‘这是程序运行信息’
[x] Received ‘这是警告’
[*] Waiting for messages. To exit press CTRL+V
[x] Received ‘zs这是错误信息’
[x] Received ‘ls这是程序运行信息’
[x] Received 'ww这是警告

发布了21 篇原创文章 · 获赞 1 · 访问量 8051

猜你喜欢

转载自blog.csdn.net/AIfurture/article/details/103645863