目录

 

开发步骤

引入client

生产者

消费者

应用场景

简单队列

工作队列

发布/订阅

路由模式

topic模式

rpc模式

发布确认


开发步骤

引入client

<dependency>
	<groupId>com.rabbitmq</groupId>
	<artifactId>amqp-client</artifactId>
	<version>5.2.0</version>
</dependency>

生产者

1、引入类

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

2、创建Connection

ConnectionFactory factory = new ConnectionFactory();
	// 设置服务地址
	factory.setHost("127.0.0.1");
	// 端口
	factory.setPort(5672);
	// vhost
	factory.setVirtualHost("/vhost_test");
	// 用户名
	factory.setUsername("admin");
	// 密码
	factory.setPassword("123456");
	Connection connection = factory.newConnection();

3、创建Channel

Channel channel = connection.createChannel()

channel设置:

 

4、声明交换器、队列

channel.queueDeclare(QUEUE_NAME, false, false, false, null);

exchange声明:

DeclareOk exchangeDeclare(String exchange, String type) throws IOException;
DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException;
DeclareOk exchangeDeclare(String exchange, String type, boolean durable) throws IOException;
DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException;
DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, Map<String,Object> arguments) throws IOException;
DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, Map<String,Object> arguments) throws IOException;
DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map<String,Object> arguments) throws IOException;
DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String,Object> arguments) throws IOException;

 参数说明:

  • exchange:exchange名称
  • type:exchange类型,BuiltinExchangeType 枚举类型包括:fanout,direct,topic,header。
  • durable:是否持久化
  • internal:是否内部exchange,生产者不能直接发布到内部exchange。
  • arguments:其他参数,用于构造exchange。

队列声明:

DeclareOk queueDeclare() throws IOException;
DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String,Object> arguments) throws IOException;

参数说明:

  • queue:队列名称
  • durable:是否持久化
  • exclusive:是否私有,仅当前程序可访问。
  • autoDelete:当最后一个消费者取消订阅后,自动删除。
  • arguments:其他参数,创建queue时使用。

 

5、发送消息

String message = "Hello World!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());

 

void basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body) throws IOException;	
void basicPublish(String exchange, String routingKey, boolean mandatory, AMQP.BasicProperties props, byte[] body) throws IOException;
void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate, AMQP.BasicProperties props, byte[] body) throws IOException;

参数说明:

  •  exchange:
  • routingKey:
  • props:消息属性
  • body:消息体的byte[]格式。
  • mandatory:当mandatory标志位设置为true时,如果exchange根据自身类型和消息routeKey无法找到一个符合条件的queue,那么会调用basic.return方法将消息返回给生产者(Basic.Return + Content-Header + Content-Body);当mandatory设置为false时,出现上述情形broker会直接将消息扔掉。
  • immediate:当immediate标志位设置为true时,如果exchange在将消息路由到queue(s)时发现对于的queue上么有消费者,那么这条消息不会放入队列中。当与消息routeKey关联的所有queue(一个或者多个)都没有消费者时,该消息会通过basic.return方法返还给生产者。

mandatory标志告诉服务器至少将该消息route到一个队列中,否则将消息返还给生产者;immediate标志告诉服务器如果该消息关联的queue上有消费者,则马上将消息投递给它,如果所有queue都没有消费者,直接把消息返还给生产者,不用将消息入队列等待消费者了。

在RabbitMQ3.0以后的版本里,去掉了immediate参数的支持,发送带immediate标记的publish会返回如下错误:
“{amqp_error,not_implemented,“immediate=true”,‘basic.publish’}”,immediate标记会影响镜像队列性能,增加代码复杂性,并建议采用“TTL”和“DLX”等方式替代。

 

消费者

1、引入类

同生产者

2、创建Connection

同生产者

3、创建Channel

同生产者

4、声明交换器,队列

同生产者

5、构造Consumer

// 创建消费者
	Consumer consumer = new DefaultConsumer(channel) {
					// 获取消息
		@Override
		public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
				throws IOException {
			String msg = new String(body, "utf-8");
			System.out.println("接收到消息——" + msg);
		}

	};

6、接收消息并处理

// 监听队列
		channel.basicConsume(QUEUE, true, consumer);
String basicConsume(String queue, Consumer callback) throws IOException
String basicConsume(String queue, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException
String basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, Map<String,Object> arguments, Consumer callback) throws IOException
String basicConsume(String queue, boolean autoAck, Map<String,Object> arguments, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, boolean autoAck, Map<String,Object> arguments, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, Map<String,Object> arguments, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, Consumer callback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map<String,Object> arguments, Consumer callback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map<String,Object> arguments, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map<String,Object> arguments, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map<String,Object> arguments, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException

参数说明:

  • queue:队列名称。
  • autoAck:服务器收到消息后是否自动应答。
  • consumerTag:消费者标签,用来区分多个消费者
  • noLocal:设置为true,表示 不能将同一个Conenction中生产者发送的消息传递给这个Connection中 的消费者
  • exclusive:是否排他
  • arguments:消费者的参数
  • callback:消费者 DefaultConsumer,用于消费消息,需要重写其中的方法
  • 其他callback
public interface Consumer {
	//Called when the consumer is cancelled for reasons other than by a call to Channel.basicCancel(java.lang.String).
	void	handleCancel(String consumerTag)
	//	Called when the consumer is cancelled by a call to Channel.basicCancel(java.lang.String).	
	void	handleCancelOk(String consumerTag)
	//Called when the consumer is registered by a call to any of the Channel.basicConsume(java.lang.String, com.rabbitmq.client.Consumer) methods.
	void	handleConsumeOk(String consumerTag)	
	//Called when a basic.deliver is received for this consumer.
	void	handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)	
	//Called when a basic.recover-ok is received in reply to a basic.recover.
	void	handleRecoverOk(String consumerTag)	
	//	Called when either the channel or the underlying connection has been shut down.
	void	handleShutdownSignal(String consumerTag, ShutdownSignalException sig)
}
  • handleCancel:除了调用basicCancel的其他原因导致消息被取消时调用。
  • handleCancelOk:basicCancel调用导致的订阅取消时被调用。
  • handleConsumeOk:任意basicComsume调用导致消费者被注册时调用。
  • handleDelivery:消息接收时被调用。
  • handleRecoverOk:basic.recover-ok被接收时调用
  • handleShutdownSignal:当Channel与Conenction关闭的时候会调用。

应用场景

各场景比较

应用场景

exchange

队列

生产者端

消费者端

简单队列


单个队列

发送到指定队列

自动应答

工作队列


多个队列

发送到指定队列

自动应答/    手动应答,公平分发

发布/订阅

fanout

多个队列

发送到指定exchange,不设置routing key

消费指定队列。

路由模式

direct

多个队列

发送到指定exchange,设置routing key

消费指定队列。指定1个或者多个binging key

topic模式

topic

多个队列

发送到指定exchange,设置routing key。key中包含点号(.)。

消费指定队列。指定1个或者多个binging key,key中包含点号(.)。

rpc

 

 

 

 

发布确认

 

 

 

 

简单队列

生产者直接发送消息到队列,消费者直接消费队列消息。

java rabbitmq 源码 rabbitmq开发_服务器

/*生产者代码  */
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World!";
//直接发送消息到队列。exchange参数为""
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
/* 消费者代码 */
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);

//定义消息消费
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
    String message = new String(delivery.getBody(), "UTF-8");
    System.out.println(" [x] Received '" + message + "'");
};
//开始消费
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });

 

工作队列

一般在实际应用中,生产者发送消息耗时较少,反应较快,反而是消费者因为要处理业务逻辑,处理时间可能会很慢,这样队列中会积压很多消息,所以需要多个消费者分摊压力,这个时候可以使用工作队列。

java rabbitmq 源码 rabbitmq开发_参数说明_02

生产者消费者代码与简单队列一样,差别为运行多个消费者代码实例。

消费者默认采用Round-robin方式轮询分发,每个消费者接收到的消息数基本一样。如果消费者处理消息速度不一致,会导致一个空闲,一个繁忙。

可以采用公平模式,如果消费者未处理完消息,则队列不会再发送消息给此消费者,只到上一条消息处理完。

java rabbitmq 源码 rabbitmq开发_java_03

 修改:

  • 添加channel.basicQos(1):保证一次只分发一条消息。
int prefetchCount = 1;
//设置每次仅接收1条消息。
channel.basicQos(prefetchCount);
  • channel.basicAck(envelope.getDeliveryTag(), false):手动确认消息。false表示确认接收消息,true表示拒绝接收消息。
try {
    doWork(message);
  } finally {
    System.out.println(" [x] Done");
    //手动确认消息
    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
  }
  • channel.basicConsume(QUEUE, false, consumer):设置自动应答为false。
channel.basicConsume(TASK_QUEUE_NAME, false, deliverCallback, consumerTag -> { });

 

发布/订阅

生产者没有把消费发送给队列,而是发送给exchange,由exchange进行路由到绑定的队列,消费者仅消费对应队列,例如事件通知通过邮件和短信进行通知。

exchange的类型为fanout

java rabbitmq 源码 rabbitmq开发_java rabbitmq 源码_04

private static final String EXCHANGE_NAME = "logs";


//声明一个exchange:logs
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");

//发送消息到exchange:logs
channel.basicPublish( "logs", "", null, message.getBytes());

 

private static final String EXCHANGE_NAME = "logs";

	//声明exchange:logs
    channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
	//声明一个随机名称的临时队列
    String queueName = channel.queueDeclare().getQueue();
	//绑定队列与exchange
    channel.queueBind(queueName, EXCHANGE_NAME, "");

    

    DeliverCallback deliverCallback = (consumerTag, delivery) -> {
        String message = new String(delivery.getBody(), "UTF-8");
        System.out.println(" [x] Received '" + message + "'");
    };
	//开始消费临时队列:
    channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });

 

路由模式

exchange类型为direct

java rabbitmq 源码 rabbitmq开发_java rabbitmq 源码_05

private static final String EXCHANGE_NAME = "direct_logs";
  
//指定exchange为direct
channel.exchangeDeclare(EXCHANGE_NAME, "direct");

String severity = getSeverity(argv);
String message = getMessage(argv);
//指定routing key:severity
channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes("UTF-8"));
//声明exchange:类型为:direct
    channel.exchangeDeclare(EXCHANGE_NAME, "direct");
    String queueName = channel.queueDeclare().getQueue();


	//绑定队列与exchange,routing key:severity
    for (String severity : argv) {
        channel.queueBind(queueName, EXCHANGE_NAME, severity);
    }
    

    DeliverCallback deliverCallback = (consumerTag, delivery) -> {
        String message = new String(delivery.getBody(), "UTF-8");
        System.out.println(" [x] Received '" +
            delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
    };
	//消费消息
    channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
  }

 

topic模式

exchange类型为topic

topic模式与direct模式代码一样,区别为binding key与routing key 必须包含点号(.)。

 

java rabbitmq 源码 rabbitmq开发_java rabbitmq 源码_06

channel.exchangeDeclare(EXCHANGE_NAME, "topic");

String routingKey = getRouting(argv);
String message = getMessage(argv);

channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes("UTF-8"));

 

channel.exchangeDeclare(EXCHANGE_NAME, "topic");
    String queueName = channel.queueDeclare().getQueue();


    for (String bindingKey : argv) {
        channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
    }

    System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

    DeliverCallback deliverCallback = (consumerTag, delivery) -> {
        String message = new String(delivery.getBody(), "UTF-8");
        System.out.println(" [x] Received '" +
            delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
    };
    channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });

 

rpc模式

发布确认