RabbitMQ(三):java API

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/maniacer/article/details/87928617

创建链接

  • 声明连接工厂,设置host、port、username、password、VirtualHost等信息,VirtualHost默认为"/",可以不设置
ConnectionFactory factory = new ConnectionFactory();
// 自己的服务器配置
factory.setHost("192.168.0.1");
factory.setPort(5672);
factory.setUsername("admin");
factory.setPassword("admin");
factory.setVirtualHost("/");
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();

定义交换器

  • 这里声明了一个名字为user.exchange的、direct类型的、持久化的、非自动删除的队列,代码如下:
	// 成员变量声明、之后代码也会调用此处成员变量
    private static final String EXCHANGE_NAME = "user.exchange";
    private static final String USER_QUEUE = "user.queue";
    private static final String ROUTING_KEY = "direct_routingkey";
	
	channel.exchangeDeclare(EXCHANGE_NAME, "direct", true);
  • 参数详解

exchange:交换器名称

type:交换器类型

durable:是否持久化,默认否、如需请声明为true

autoDelete:是否自动删除交换器,删除条件为:autoDelete设置为true,至少有一个队列或交换器与这个交换器绑定(被使用过)、之后所有与之绑定的队列或交换器都与之解绑。并不是当与之连接的客户端都断开时,RabbitMQ自动删除本交换器。默认为否

internal:设置是否是内置交换器。如果为true,表示是内置交换器,客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式。默认非内置

arguments:其他一些结构化参数,比如 alternate-exchange,暂且不关注这个字段,传null就好

  • exchangeDeclare的重载方法。一般地,使用exchangeDeclare(String exchange, String type, boolean durable)就够了,其余参数视情况而定
    Exchange.DeclareOk exchangeDeclare(String exchange, String type) throws IOException;
    
    Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException;
    
    Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable) throws IOException;
    
    Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException;

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

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

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

    Exchange.DeclareOk exchangeDeclare(String exchange,
        BuiltinExchangeType type,
        boolean durable,
        boolean autoDelete,
        boolean internal,
        Map<String, Object> arguments) throws IOException;
  • exchangeDeclareNoWait方法
    exchangeDeclare与exchangeDeclareNoWait很相似,exchangeDeclareNoWait多了一个noWait参数,意思是:在服务器声明了一个exchange之后,不需要返回Declare-OK指令、exchange就可以使用,效率稍许提升,可是带来一个问题:当刚刚声明一个exchange之后(还未确认OK)、立即使用exchange就会抛出异常,因此这个方法一般不考虑。
  • exchangeDeclarePassive方法
    这个方法用来检测相应的交换器是否存在。如果存在就正常返回,如果不存在就抛出异常,同时channel也会关闭。
  • exchangeDelete方法
    删除交换器,ifUnused:true,代表如果此交换器被使用中、则删除失败。有三种实现形式,如下:
    Exchange.DeleteOk exchangeDelete(String exchange, boolean ifUnused) throws IOException;

    void exchangeDeleteNoWait(String exchange, boolean ifUnused) throws IOException;

    Exchange.DeleteOk exchangeDelete(String exchange) throws IOException;

定义队列

  • 这里定义了一个名字为user.queue、持久化存储的、非排他的、非自动删除的队列
channel.queueDeclare(USER_QUEUE, true, false, false, null);
  • queueDeclare的重载方法不多、连带noWait方法/Passive方法一起、如下:
    Queue.DeclareOk queueDeclare() throws IOException;

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

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

其中无参方法实现为:

@Override
    public com.rabbitmq.client.AMQP.Queue.DeclareOk queueDeclare()
        throws IOException
    {
        return queueDeclare("", false, true, true, null);
    }
  • 参数详解

queue:队列名称

durable:是否持久化、默认false

exclusive:是否排他、默认true。如果一个队列被声明为排他队列,该队列仅对首次声明它的链接可见,并在该connection断开连接时删除。这里需要注意三点:排他队列是基于连接( Connection) 可见的,同一个连接的不同信道 (Channel)是可以同时访问同一连接创建的排他队列; "首次"是指如果一个连接己经声明了 一个排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同:即使该队列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除,这种队列适用于一个客户端同时发送和读取消息的应用场景

autoDelete:是否自动删除、默认true

arguments:设置队列的其他一些参数,如 x-rnessage-ttl 、 x-expires 、x -rnax-length 、 x-rnax-length-bytes 、 x-dead-letter-exchange 、 x-deadletter-routing-key, x-rnax-priority 等

  • 删除队列
Queue.PurgeOk queuePurge(String queue) throws IOException;

队列交换器绑定

  • 如下,将队列USER_QUEUE和交换器EXCHANGE_NAME绑定,路由键为ROUTING_KEY
channel.queueBind(USER_QUEUE, EXCHANGE_NAME, ROUTING_KEY);
  • queueBind有两个重载方法
    Queue.BindOk queueBind(String queue, String exchange, String routingKey) throws IOException;

    Queue.BindOk queueBind(String queue, String exchange, String routingKey, Map<String, Object> arguments) throws IOException;
  • 属性详解
    queue:队列名
    exchange:交换器名
    arguments:定义绑定的一些参数
  • queueBind还有一个noWait方法。还有解绑的两个重载方法,如下:
    void queueBindNoWait(String queue, String exchange, String routingKey, Map<String, Object> arguments) throws IOException;

    Queue.UnbindOk queueUnbind(String queue, String exchange, String routingKey) throws IOException;

    Queue.UnbindOk queueUnbind(String queue, String exchange, String routingKey, Map<String, Object> arguments) throws IOException;

交换器与交换器绑定

我们不仅可以将交换器与队列绑定,也可以将交换器与交换器绑定,用法极为类似,接口如下:

    Exchange.BindOk exchangeBind(String destination, String source, String routingKey) throws IOException;

    Exchange.BindOk exchangeBind(String destination, String source, String routingKey, Map<String, Object> arguments) throws IOException;

    void exchangeBindNoWait(String destination, String source, String routingKey, Map<String, Object> arguments) throws IOException;

    Exchange.UnbindOk exchangeUnbind(String destination, String source, String routingKey) throws IOException;

    Exchange.UnbindOk exchangeUnbind(String destination, String source, String routingKey, Map<String, Object> arguments) throws IOException;

    void exchangeUnbindNoWait(String destination, String source, String routingKey, Map<String, Object> arguments) throws IOException;
  • 交换器绑定交换器的意义在于:多个生产者需要输出到同一个队列,供同一类型的消费者消费,多个生产者就可以通过绑定交换器、最终将消息输出到同一交换器的队列。
    交换器绑定交换器

发送消息

  • 发送消息时,指定交换器名、路由键、待序列化的数据即可,当然还有很多附加字段
// 发送对象、注意:对象必须实现Serialization接口
User user = new User();
user.setId(2);
user.setUsername("陈独秀");
user.setAge(25);
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, null, SerializationUtils.serialize(user));

// 发送字符串
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, null, "Hello 世界".getBytes());
  • basicPublish共有三个重载方法
    void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;

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

    void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate, BasicProperties props, byte[] body) throws IOException;
  • 属性详解

exchange:交换器名称

routingKey:路由键

mandatory:当设置为true时,交换器无法根据自身的类型和路由键找到一个符合条件的队列,那么RabbitMQ会调用Basic.Return命令将消息返回给生产者。

immediate:当设置为true时,如果交换器在将消息路由到队列时发现队列上并不存在任何消费者,那么这条消息将不会存储队列中。当与路由键匹配的所有队列都没有消费者时,该消息会通过Basic.Return返回给生产者。

概括来说 , mandatory 参数告诉服务器至少将该消息路由到一个队列 中, 否则将消息返回给生产者。 immediate参数告诉服务器 , 如果该消息关联的队列上有消费者, 则 立刻投递:如果所有匹配的队列上都没有消费者,则直接将消息返还给生产者 , 不用将消息存入队列而等待消费者了。

但是RabbitMQ3.0版本开始去掉了对immediate的支持,对此RabbitMQ官网解释是:immediate参数会影响镜像队列的性能,增加了代码的复杂性,建议采用TTL和DLX的方法替代。

props:消息的基本属性集。其包含 14 个属性成员,分别有 contentType 、content Encoding 、 headers (Map<String , Object>) 、 deliveryMode 、 priority 、correlationld 、 replyTo 、 expiration 、 messageld、 timestamp 、 type 、 userld 、appld 、 clusterld

body:消息体,payload,待发送的消息主体

消费消息

关闭链接

  • 先关闭channel、然后关闭connection。关闭逻辑应在finally中定义
if (channel != null) {
    try {
        channel.close();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (TimeoutException e) {
        e.printStackTrace();
    }
}
if (conn != null) {
    try {
        conn.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

猜你喜欢

转载自blog.csdn.net/maniacer/article/details/87928617