安装rabbitMQ后下面就是rabbitMQ在JAVA环境下的使用了
博主在网上翻了很久也没找到一本用java环境写的关于rabbitMQ的书,有一本也是用python做语言环境编写的书《RabbitMQ实战++高效部署分布式消息队列》应该是这个名字,博主不会上传附件请自行搜索
直接上代码
package com.lzdn; /** * 初始抽象类 */ import java.io.IOException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; public abstract class EndPoint { protected Channel channel; protected Connection connection; protected String endPontName; public EndPoint(String endpointName) throws IOException{ this.endPontName = endpointName; ConnectionFactory factory = new ConnectionFactory(); factory.setHost("192.168.16.201"); //插入端口 默认选用默认端口 //factory.setPort(port); factory.setUsername("admin"); factory.setPassword("admin"); connection=factory.newConnection(); channel=connection.createChannel(); /** * 声明一个交换器 */ //channel.exchangeDeclare("this", "topic", true, false, null); /** * 声明一个队列 * channel.queueDeclare(queue, durable, exclusive, autoDelete, arguments); * @param queue 队列的名称 * @param durable 如果我们声明一个持久队列(队列将在服务器重新启动后继续存在),则设置为ture * @param exclusive 如果我们声明一个独占队列(仅限于此连接),则独占 设置为 true * @param autoDelete 如果我们声明一个自动删除队列(服务器将在不再使用时删除它) 设置为 true * @param arguments 队列的其他属性(构造参数)。 */ channel.queueDeclare(endpointName, false, false, false, null); /** * 将交换器和队列绑定 */ //channel.queueBind(queue, exchange, routingKey) } public void close() throws IOException{ this.channel.close(); this.connection.close(); } }
package com.lzdn; import java.io.IOException; import java.io.Serializable; import org.apache.commons.lang.SerializationUtils; /** * 生产者 * @author chuan * */ public class Producer extends EndPoint{ public Producer(String endpointName) throws IOException { super(endpointName); } public void sendMessage(Serializable object)throws IOException{ /** * Parameters: * exchange: the exchange to publish the message/ * toroutingKey: the routing key * (默认的exchange:如果用空字符串去声明一个exchange,那么系统就会使用”amq.direct”这个exchange, * 我们创建一个queue时,默认的都会有一个和新建queue同名的routingKey绑定到这个默认的exchange上去) * props: other properties for the message - routing headers etc * body: the message body * channel.basicPublish(exchange, routingKey, props, body); */ channel.basicPublish("", endPontName, null, SerializationUtils.serialize(object)); } }
package com.lzdn; import java.io.IOException; import java.util.Map; import org.apache.commons.lang.SerializationUtils; import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.Consumer; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.ShutdownSignalException; public class QueueConsumer extends EndPoint implements Runnable,Consumer{ public QueueConsumer(String endpointName) throws IOException { super(endpointName); } public void handleCancel(String arg0) throws IOException { } public void handleCancelOk(String arg0) { } /** * Called when consumer is registered. * 当用户注册时调用。 */ public void handleConsumeOk(String consumerTag) { System.out.println("Consumer " + consumerTag + " registered"); } /** * Called when new message is available. * 当新消息可用时调用。 */ public void handleDelivery(String consumerTag, Envelope env, BasicProperties props, byte[] body) throws IOException { Map map = (Map) SerializationUtils.deserialize(body); System.out.println(Thread.currentThread().getStackTrace()[1].getFileName()+"Message Number " + map.get("message number") + " received."); /** * 当channel.basicConsume(endPontName, false, this);设置为false时需要打开消息应答 */ channel.basicAck(env.getDeliveryTag(), false); } public void handleRecoverOk(String arg0) { } public void handleShutdownSignal(String arg0, ShutdownSignalException arg1) { } public void run() { try { /** * @param autoAck true if the server should consider messages * acknowledged once delivered; false if the server should expect * 设置basicConsume方法参数为false,打开消息应答 */ channel.basicConsume(endPontName, false, this); }catch (Exception e) { e.printStackTrace(); } } }
package com.lzdn; import java.io.IOException; import java.util.HashMap; public class Main { public Main() throws IOException { //启动消费者 QueueConsumer consumer = new QueueConsumer("queue"); Thread consumerThread = new Thread(consumer); consumerThread.start(); //test2.启动第二个消费者 进入轮询模式 QueueConsumer2 consumer2 = new QueueConsumer2("queue"); Thread consumerThread2 = new Thread(consumer2); consumerThread2.start(); // Producer producer = new Producer("queue"); for (int i = 0; i < 20; i++) { HashMap message = new HashMap(); message.put("message number", i); producer.sendMessage(message); System.out.println("Message Number " + i + " sent."); } } public static void main(String[] args) throws IOException { Main ssd = new Main(); } }
在不去设置exchange(交换器时),rabbitmq 默认为Direct exchange模式即直连交换机,该模式为根据rutingKey将数据发送到指定队列(这里要区分理解rabbitmq的4个阶段数据<个人理解>:传入阶段,交换机阶段,队列阶段,消费者消费阶段),
java环境下创建exchange即
channel.exchangeDeclare("this", "topic", true, false, null);//该方法创建一个exchange即交换器
该方法的第一个参数为指定exchange的名字,第二个参数为exchange的类型(即4大交换器),第三个参数为该交换器是否为持久化(true持久化,false不进行持久化)第四个参数是在不使用该交换器后该交换器是否自动删除(true自动删除,false不制动删除),第五个参数为其他构造参数
channel.queueDeclare(endpointName, false, false, false, null);//该方法创建一个队列各个参数解释在上面的代码里已经体现 就不在说了
channel.queueBind(queue, exchange, routingKey);//该方法就是将一个队列与交换器进行连接并指定寻道routingKey
channel.basicPublish(exchange, routingKey, props, body); //该方法为向指定交换器传入信息,exchange是指定交换器的名字,routingKey为该交换器下的寻道方法,props为头信息,body就是具体消息内容
一个消息传入的整个过程为:首先查询exchange找到对应的交换器-》如果不填交换器时指定到默认交换器中,如果有交换器就发送到指定交换器-》发送到指定交换器后根据routingKey放入对应队列
一个消息接收的整个过程为:创建一个指定queue名字的接收器,启动线程监听端口,直到接收到输出-》如果不需要返回确认的话在处理后继续监听端口等待新的信息传入,如果需要返回确认在返回确认后继续监听等待新的信息传入(需要确认返回信息的接收器如果无法返回信息那么该条信息会返还给队列,即在队列中不删除该条信息)