RabbitMQ几种常用模式

爱⌒轻易说出口 提交于 2020-01-12 17:28:07

rabbitmq

/**
 * 连接工具类
 */
public class ConnectionUtil {
    /**
     * 建立与RabbitMQ的连接
     * @return
     * @throws Exception
     */
    public static Connection getConnection() throws Exception {
        //定义连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //设置服务地址
        factory.setHost("127.0.0.1");
        //端口
        factory.setPort(5672);
        //设置账号信息,用户名、密码、vhost
//Virtual代表虚拟消息服务器,每个服务器相对独立
        factory.setVirtualHost("/");
        factory.setUsername("guest");
        factory.setPassword("guest");
        // 通过工程获取连接
        Connection connection = factory.newConnection();
        return connection;
    }
}

1.hello world

简单的说就是

一个消息发送者,一个队列,一个消息接受者
在这里插入图片描述消息发送者

public class Sen {

    //队列的名字
    private static final String QUEUE_HELLO = "queue_hello";

    public static void main(String[] args) {
        Connection connection = null;
        Channel channel = null;
        try{
            //1.创建链接对象
            connection = ConnectionUtil.getConnection();

            //2.创建通道
            channel = connection.createChannel();

            //3.声明队列:队列名字 ; 持久 ;独占链接 ;不用即删除 ; 参数
            channel.queueDeclare(QUEUE_HELLO, true, false, false, null);

            //4.发送消息:交换机 ; 队列名(routingkey) ;参数 ;消息了内容

            for (int i = 0 ; i<10; i++){
                String str = "axiba"+i;
                channel.basicPublish("", QUEUE_HELLO ,null ,str.getBytes() );
                System.out.println("消息已经发出:"+str);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(channel != null){
                try {
                    channel.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }


    }
}

消息接受者

public class Rev {
    //队列的名字
    private static final String QUEUE_HELLO = "queue_hello";
    public static void main(String[] args) {
        try {
            //1.创建链接
            Connection connection = ConnectionUtil.getConnection();

            //2.创建通道
            Channel channel = connection.createChannel();

            //3.声明队列
            //队列名,是否持久化,是否独占一个队列,是否用完后删除队列,其他参数
            channel.queueDeclare(QUEUE_HELLO, true, false, false, null);

            //回调函数,接收到消息时调用,匿名内部类
            Consumer consumer = new DefaultConsumer(channel){
                /**
                 * 消息的方法
                 * @param consumerTag  消费者id
                 * @param envelope
                 * @param properties
                 * @param body
                 * @throws IOException
                 */
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope,
                                           AMQP.BasicProperties properties, byte[] body)throws IOException {

                    System.out.println("consumerTag"+consumerTag);
                    //交换机
                    String exchange = envelope.getExchange();
                    System.out.println("exchange:"+exchange);
                    //路由key
                    String routingKey = envelope.getRoutingKey();
                    System.out.println("routingKey:"+routingKey);
                    //消息id
                    long deliveryTag = envelope.getDeliveryTag();
                    System.out.println("deliveryTag:"+deliveryTag);
                    //消息内容
                    String msg = new String(body, "utf8");
                    System.out.println("收到消息:" + msg);
                    //手动签收
                    channel.basicAck(deliveryTag, true);
                }
            };

            //4.接受消息 :队列 ; 签收方式(true:自动签收)  false关闭自动签收
            channel.basicConsume(QUEUE_HELLO, false,consumer);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

2. work

简单的说是

一个消息发送者,一个队列,两个消息接受者

默认是轮询发送给每一个消息的接受者

但是可以加一行代码,谁有能力谁接受更多java

//处理一条消息
channel.basicQos(1);

在这里插入图片描述和helloworld差不多,只是多了一个消息接收方,连接的是同一个队列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PKBKcV8n-1578480419297)(C:\Users\LSDN-ASUS\AppData\Roaming\Typora\typora-user-images\image-20200108164357797.png)]

唯一的差别就是,如果各自处理问题的效率不一样,为了更好的利用效率高的一方,我们会加一句代码

//处理一条消息
channel.basicQos(1);

3.订阅/发布

1.fanout—广播

一个消息发送者,一个交换机,多个队列对应多个消息接受者

所有队列绑定到交换机,就能接受到所有消息

在这里插入图片描述
fanout就是交换机发送,所有都能接收,和前面两种不一样的是这里开始引入了交换机

我们在消息发送者那边就不会声明队列而是声明交换机

public static final String EXCHANGE_FANOUT = "exchange_fanout";

//声明交换机
channel.exchangeDeclare(EXCHANGE_FANOUT, BuiltinExchangeType.FANOUT);

队列在消息接受者这边声明并进行绑定

public static final String QUEUE_FANOUT = "queue_fanout1";

//队列名,是否持久化,是否独占一个队列,是否用完后删除队列,其他参数
channel.queueDeclare(QUEUE_FANOUT, true, false, false, null);
//绑定到交换机
channel.queueBind(QUEUE_FANOUT,Sen.EXCHANGE_FANOUT,"");

发送消息没有指定routingkey,因为所有队列都可以收到

channel.basicPublish(EXCHANGE_FANOUT, "" ,null ,str.getBytes() );

2.direct—指定

一个生产者,一个交换机,多个队列

但是有的队列可以指定多个routingkey,来接收更多的消息
在这里插入图片描述
direct与fanout,的区别就是

direct会把消息发送到交换机中,但是只有routingkey一致的消息接受者才能接受到消息。

channel.basicPublish(EXCHANGE_DIRECT,"user.delete",null,msg.getBytes());

这样就只有routingkey为user.delete的消息接受者能收到

3.topic—通配符

一个生产者,一个交换机,多个队列

但是有的队列可以指定多个routingkey,通配符,来接收更多的消息

#:匹配多个单词

*:匹配一个单词
在这里插入图片描述
topic–与前面的fanout和direct的区别

其实topic类似于direct,都是匹配上routingkey的消息接收方才能收到消息

差别就是,direct是指定明确了具体的routingkey,而topic是指定了符合规范的一类routingkey

//发布消息
channel.basicPublish(EXCHANGE_TOPIC,
                     "user.insert.insertmore",
                     null,message.getBytes());

比如这里我们发送的消息是发送到交换机中,他的routingkey是user.insert.insertmore

//将队列绑定到交换机中
channel.queueBind(QUEUE_TOPIC,Sen.EXCHANGE_TOPIC,"user.*");

这是我其中一个接收者,绑定到交换机的时候,他的通配符是*

能匹配类似于 user.insert , user.delete …等这类的routingkey

因为*表示一个单词

//将队列绑定到交换机中
channel.queueBind(QUEUE_TOPIC,Sen.EXCHANGE_TOPIC,"user.#");

这是我另一个接收者,绑定到交换机的时候,他的通配符是#

能匹配类似于 user, user.insert , user.insert . insertmore , user. xx. yy. zz…

所有user开头的routingkey

因为#表示0到多个

结果就是前面发送的消息,只有#这边能接收到,而*不能

持久化

1.交换机持久化

//声明交换机  true,代表持久化开启
channel.exchangeDeclare(EXCHANGE_TOPIC, BuiltinExchangeType.TOPIC,true);

2.队列持久化

//声明队列  第二个参数true--代表队列持久化
channel.queueDeclare(QUEUE_TOPIC,true,false,false,null);

3.消息持久化

//发布消息  MessageProperties.PERSISTENT_TEXT_PLAIN
channel.basicPublish(EXCHANGE_TOPIC,"user.insert.insertmore",    
   	  		MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes());
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!