rabbitmq学习(2)——java实现简单队列

一、创建maven-java项目

创建maven项目工程,实现简单消息队列操作。
在这里插入图片描述
简单消息图示信息解释:

P:消息生产者
C 消息消费者

二、依赖引入

	<dependencies>
		<dependency>
			<groupId>com.rabbitmqgroupId>
			<artifactId>amqp-clientartifactId>
			<version>4.0.2version>
		dependency>
		<dependency>
			<groupId>org.slf4jgroupId>
			<artifactId>slf4j-apiartifactId>
			<version>1.7.10version>
		dependency>
		<dependency>
			<groupId>org.slf4jgroupId>
			<artifactId>slf4j-log4j12artifactId>
			<version>1.7.5version>
		dependency>
		<dependency>
			<groupId>log4jgroupId>
			<artifactId>log4jartifactId>
			<version>1.2.17version>
		dependency>
		<dependency>
			<groupId>junitgroupId>
			<artifactId>junitartifactId>
			<version>4.11version>
		dependency>
	dependencies>

三、java代码

3.1、编写连接工具类

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class MqConnectUtil {
	
	/**
	 * 获取mq的连接
	 * @return
	 * @throws TimeoutException 
	 * @throws IOException 
	 */
	public static Connection getMqConnection() throws IOException, TimeoutException{
		//1、定义一个连接工厂
		ConnectionFactory factory = new ConnectionFactory();
		//2、设置连接地址等信息
		factory.setHost("127.0.0.1");
		//amqp协议端口
		factory.setPort(5672);
		//设置具体的vhost(想象成数据库)
		factory.setVirtualHost("/xiangjiao");
		//设置用户名密码信息
		factory.setUsername("xiangjiao");
		factory.setPassword("bunana");
		
		return factory.newConnection();
	}
}

3.2、编写发送信息类

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import cn.linkpower.util.MqConnectUtil;

/**
 * 简单消息队列 生产者
 * @author 76519
 *
 */
public class Send {
	private static String simpleQueueName = "test_simple_queue";
	public static void main(String[] args) throws Exception{
		//创建一个连接
		Connection conn = MqConnectUtil.getMqConnection();
		//构建一条通道 --- 从连接中获取一个通道
		Channel createChannel = conn.createChannel();
		//申明一个指定的队列
		createChannel.queueDeclare(simpleQueueName,
				false, false, false, null);
		
		//发送数据信息
		String msg = "hello xiangjiao bunana";
		//发送数据
		createChannel.basicPublish("", 
				simpleQueueName, null, msg.getBytes());
		
		System.out.println("---send msg = "+msg);
		
		//关闭流和连接
		createChannel.close();
		conn.close();
	}
}

我们在操作 rabbitmq时,可以将其看作一个数据库(mysql、oracle等),相关操作和数据库jdbc操作很类似。在使用前,需要指明详细的哪个消息队列;在使用完成后,因为他的操作属于IO流操作,所以为了节省资源和避免出现不必要bug,需要及时的对流进行关闭操作。

3.3、查看消息

在运行上述代码之后,我们如何才能知道消息是否添加至队列中了呢?

3.3.1、进入本地浏览器页面,输入账号密码信息

3.3.2、进入指定的queue中,查看相关信息

rabbitmq学习(2)——java实现简单队列_第1张图片
点击我们在java代码中设定的名称后,我们会进入另外一个页面,找到Get Messages项,展开列表
rabbitmq学习(2)——java实现简单队列_第2张图片
选择 Get Message按钮后,则会出现上述已发送的信息。
rabbitmq学习(2)——java实现简单队列_第3张图片
这里需要注意一点:当获取了其中的消息后,这个队列中也就没有这个消息了。

实际开发中,我们不可能每次手动去网址上取数据,所以必须使用一个另外的代码去自动获取相关的消息,当有消息生产者提供了消息后,消息消费者则需要自动获取相关的消息。如何用代码实现自动获取呢?

3.4、自动获取消息

3.4.1、使用一个已过时的方式获取

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConsumerCancelledException;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;
import com.rabbitmq.client.ShutdownSignalException;

import cn.linkpower.util.MqConnectUtil;

/**
 * 使用程序代码获取send端发送的消息(从mq中自动取得)
 * @author 76519
 *
 */
public class GetMqMsg_old {
	private static String simpleQueueName = "test_simple_queue";
	public static void main(String[] args) throws IOException, TimeoutException, ShutdownSignalException, ConsumerCancelledException, InterruptedException {
		//获取连接
		Connection mqConnection = MqConnectUtil.getMqConnection();
		//构建通道
		Channel createChannel = mqConnection.createChannel();
		
		//定义一个队列的消费者
		QueueingConsumer queueingConsumer = new QueueingConsumer(createChannel);
		
		//监听
		createChannel.basicConsume(simpleQueueName, true,queueingConsumer);
		
		//获取数据
		while(true){
			
			Delivery nextDelivery = queueingConsumer.nextDelivery();
			String msg = new String(nextDelivery.getBody());
			System.out.println("get old msg == "+msg);
		}
	}
}

过时的方式,我们使用的案例为创建一个指定消息队列的监听对象,又创建了一个死循环不断地去打印新的消息信息。但死循环毕竟不是最好的实现方式,所以我们需要使用新的方式实现相同的技术。

3.4.2、使用新方式监听并获取相关的队列中的消息

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import cn.linkpower.util.MqConnectUtil;

public class GetMqMsg_new {
	private static String simpleQueueName = "test_simple_queue";

	public static void main(String[] args) throws IOException, TimeoutException {
		// 获取连接
		Connection mqConnection = MqConnectUtil.getMqConnection();
		// 构建通道
		Channel createChannel = mqConnection.createChannel();

		DefaultConsumer consumer = new DefaultConsumer(createChannel) {
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
					throws IOException {
				String message = new String(body, "UTF-8");
				System.out.println(" get msg new = " + message );
			}
		};
		//监听队列
		createChannel.basicConsume(simpleQueueName, true, consumer);
	}
}

四、2019.11.04 增加笔记

不管是生产者生产消息还是消费者消费消息,都需要申明消息队列(配置消息队列)

createChannel.queueDeclare(simpleQueueName, 
				false, false, false, null);

其实原因大家都会知道的,如果在 localhost:15672中的Queues没有相关的队列信息时,如下所示:
在这里插入图片描述
没有指定的 test_simple_queue
消息消费者或生产者启动若没有进行消息队列的设置,则会出现一个异常信息。
rabbitmq学习(2)——java实现简单队列_第4张图片
出现这个问题的原因就在于,创建连接和通信管道后,此时的消息队列中不存在指定的消息,消息队列不知道是那种类型的队列(轮询、公平分发等等),才出现的报错。

之前有说到:消费者不需要再设置。
原则上是这样的,但消费者在java中采取的是监听机制,他可以在消息生产者生产消息之前就进行启动的,如果是这样的话,在消息队列中依旧不存在申明好的消息队列,运行也会出现报错信息。

你可能感兴趣的:(rabbitmq)