2021-09-17RabbitMQ

RabbitMQ

1.RabbitMQ基本知识点

1.1基本使用

直接使用不使用交换机,意思是使用的默认的交换机名称参数为:""

消费者

public class ExchangeConsumer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //获取channel,可以看成提供者的getChannel
        Channel channel = consumer.getChannel();
        //获取交换机
//        channel.exchangeDeclare("myChange", BuiltinExchangeType.DIRECT);
//        绑定队列
//        channel.queueBind("HelloWorld", "myChange", "t1");
      /*  //发送
        for (int i = 0; i < 10; i++) {
            String s = i+"弟弟大点掉";
            channel.basicPublish("myChange", "t1", null, s.getBytes());
        }*/
//      接受
    channel.basicConsume("HelloWorld1", false, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println(new String(body));
        }
    });
​
​
​
    }
}
​

提供者

public class producer {
    public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, URISyntaxException, IOException, TimeoutException {
        Channel channel = getChannel();
       
      channel.queueDeclare("HelloWorld", true, false, false, null);
        //发送消息
      for (int i = 0; i < 10; i++) {
            channel.basicPublish("", "HelloWorld", null, "嘿嘿连载".getBytes());
        }
​
        //关闭连接
       /* channel.close();
        connection.close();*/
​
    }
​
    public static Channel getChannel() throws IOException, TimeoutException {
        //获取工厂对象
        ConnectionFactory factory=new ConnectionFactory();
        //拿到连接
        factory.setHost("47.111.236.242");
        factory.setPort(5672);
        factory.setVirtualHost("/test");
        factory.setUsername("demo");
        factory.setPassword("demo");
        Connection connection = factory.newConnection();
        //获取channel
        return connection.createChannel();
    }
}
​

1.2RabbitMQ的四种交换机模式

所有交换机都对应一个

1.2.1直接交换机(Direct)

在Rabbit的java包中,有DirectExchange代表直接交换机

它通过routingkey来判断把消息发送给谁,如果没有routingkey就会报错,同时它除了表达方式可以和Topic通配交换机有一定的情况使用是相同,和其他的交换机的使用方法是一点不一样的.(路由key可以重复).

1.2.2扇形(广播)交换机(Fanout)

在Rabbit的spring整合包中,有FanoutExchange代表广播交换机

他是按照绑定情况,不分路由key的,只要进行绑定的队列都会进行发送

1.2.3通配符交换机(Topic)

在Rabbit的spring整合包中,有TopicExchange代表通配符交换机

它进行routingkey的匹配模式进行发送消息,如果绑定时设置的routingkey不符合通配符要求就不发送

注:#代表所有路径a.#代表以a.开头的所有a.c.d;

*代表单层路径a.*只能匹配a.b

  //广播
        Binding ss = BindingBuilder.bind(queue).to(new FanoutExchange("ss"));
        //适配器
        Binding aa = BindingBuilder.bind(queue).to(new TopicExchange("aa")).with("bind.#");
        //直接
        BindingBuilder.bind(queue).to(Directexchange).with("bind");
        //默认
        Exchange aa1 = new DirectExchange("aa");
        Binding bind = BindingBuilder.bind(queue).to(aa1).with("bind").noargs();

2.RabbitMQ整合spring使用

2.1环境配置

spring的环境依赖+spring整合RabbitMQ的依赖

     <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
            <version>2.1.8.RELEASE</version>
        </dependency>

2.2关于RabbitMQ在spring配置文件中如何配置

消费者

   
<!--RabbitMQ的连接工厂必须注入-->
<rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                               port="${rabbitmq.port}"
                               username="${rabbitmq.username}"
                               password="${rabbitmq.password}"
                               virtual-host="${rabbitmq.virtual-host}"/>
​
​
<!--监听器的配置,消费者必须配置监听器,这部是注册监听-->
<!--    <bean id="springQueueListener" class="com.ljr.consumer.listener.DirectListener"/>-->
    <bean id="fanoutListener1" class="com.ljr.consumer.listener.FanoutListener" />
    <bean id="fanoutListener2" class="com.ljr.consumer.listener.FanoutListener"/>
    <bean id="topicListenerStar" class="com.ljr.consumer.listener.TopicListener"/>
    <bean id="topicListenerWell" class="com.ljr.consumer.listener.TopicListener"/>
    <bean id="topicListenerWell2" class="com.ljr.consumer.listener.TopicListener"/>
<!--RabbitMQ的监听器绑定,不绑定则无法监听-->
    <rabbit:listener-container connection-factory="connectionFactory" auto-declare="true" acknowledge="none">
<!--        <rabbit:listener ref="springQueueListener" queue-names="spring_queue"/>-->
        <rabbit:listener ref="fanoutListener1" queue-names="spring_fanout_queue_1"/>
        <rabbit:listener ref="fanoutListener2" queue-names="spring_fanout_queue_2"/>
        <rabbit:listener ref="topicListenerStar" queue-names="spring_topic_queue_star"/>
        <rabbit:listener ref="topicListenerWell" queue-names="spring_topic_queue_well"/>
        <rabbit:listener ref="topicListenerWell2" queue-names="spring_topic_queue_well2"/>
    </rabbit:listener-container>

提供者

  <!-- 定义rabbitmq connectionFactory
         确认模式,提供者发送消息可以获得mq的反馈,是否接收成功(在restTelement.confirm会出现想要的方法)
         publisher-confirms="true"
            回退模式
            在发送给交换机的时候,发送失败才会实现的,有两种处理策略:
            1.直接丢弃;2返回失败消息给发送方      
         publisher-return="true"-->
    <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                               port="${rabbitmq.port}"
                               username="${rabbitmq.username}"
                               password="${rabbitmq.password}"
                               virtual-host="${rabbitmq.virtual-host}"
​
                              />
    <!--定义管理交换机、队列的RabbitAdmin对象,只有注入这个对象,才能进行交换机和队列的管理
如:
//创建交换机,无则创建有则跳过
rabbitAdmin.declareExchange(new FanoutExchange("test.exchange.fanout", true, false));
rabbitAdmin.declareExchange(new DirectExchange("test.exchange.direct", true, false));
rabbitAdmin.declareExchange(new TopicExchange("test.exchange.topic", true, false));
没有这个类就无法进行管理创建,这里没有写名字是因为spring默认给他的名字为"rabbitAdmin"
创建之后就会默认使用,无需再次标明(随便起什么名字ID)
-->
    <rabbit:admin connection-factory="connectionFactory"/>
​
    <!--定义持久化队列,不存在则自动创建;不绑定到交换机则绑定到默认交换机
    默认交换机类型为direct,名字为:"",路由键为队列的名称
    auto-delete="true"满足两个条件:
    1:首先至少有一个消费者使用过这个队列
    2:没有消费者使用这个队列
    才会进行删除
    -->
    <rabbit:queue id="spring_queue" name="spring_queue"  auto-declare="true"/>
​
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~广播;所有队列都能收到消息~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_fanout_queue_1" name="spring_fanout_queue_1"  auto-declare="true"/>
​
    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_fanout_queue_2" name="spring_fanout_queue_2"  auto-declare="true" />
​
    <!--定义广播类型交换机;并绑定上述两个队列-->
    <rabbit:fanout-exchange id="spring_fanout_exchange" name="spring_fanout_exchange"   auto-declare="true">
        <rabbit:bindings>
            <rabbit:binding queue="spring_fanout_queue_1"/>
            <rabbit:binding queue="spring_fanout_queue_2"/>
        </rabbit:bindings>
    </rabbit:fanout-exchange>
​
    <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~通配符;*匹配一个单词,#匹配多个单词 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_topic_queue_star" name="spring_topic_queue_star" auto-declare="true"/>
    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_topic_queue_well" name="spring_topic_queue_well" auto-declare="true"/>
    <!--定义广播交换机中的持久化队列,不存在则自动创建-->
    <rabbit:queue id="spring_topic_queue_well2" name="spring_topic_queue_well2" auto-declare="true"/>
​
    <rabbit:topic-exchange id="spring_topic_exchange" name="spring_topic_exchange" auto-declare="true">
        <!--#匹配所有,*只能匹配一层*a*可以匹配带有一层的带a-->
        <rabbit:bindings>
            <rabbit:binding pattern="heima.*" queue="spring_topic_queue_star"/>
            <rabbit:binding pattern="heima.#" queue="spring_topic_queue_well"/>
            <rabbit:binding pattern="itcast.#" queue="spring_topic_queue_well2"/>
        </rabbit:bindings>
    </rabbit:topic-exchange>
​
    <!--定义rabbitTemplate对象操作可以在代码中方便发送消息-->
    <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>

在消息被消费者接受时,MQ无法确认你获取到了消息是否正常处理,所以说我们在消费者接收消息之后需要告诉MQ消息是否正常处理,在连接的时候 在配置监听器容器的时候,加入 acknowledge="none/manual/auto" 自动确认/手动确认/根据异常类型确认.

如果是手动确认,我们可以重写或者实现MessageListener的子类.在其内部实现手动确认channel.basicAsk(driverTag,true);

2.3实战

在需要使用的地方依赖注入RabbitTelement,使用其方法方便我们的操作

如:

提供者

  template.convertAndSend("spring_topic_exchange", "heima.a.b", "沃德吉尔英邦邦");
​

消费者

必须定义监听器,否则无法获取消息

监听器可以通过配置文件配置如上面的消费者配置文件

监听器必须实现接口RabbitListener,或者MessageListener的实现类

public class DirectListener implements MessageListener {
    @Override
    public void onMessage(Message message) {
        System.out.println(new String(message.getBody()));
    }
​
​
}

通过Message的各种方法获取消息信息

3.RAbbitMQ整合SpringBoot

3.1.环境配置

导入springboot整合rabbitMq的包

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit-test</artifactId>
            <scope>test</scope>
        </dependency>

可以使用@ImportResource导入配置文件

也可以通过配置类

@Configuration
public class RabbitMQConfig {
/*
定义直接交换机
 */
    @Bean("springbootExchange")
    public Exchange SpringbootExchange()
    {
        return new DirectExchange("springbootExchange");
    }
    /*
    定义队列
     */
    @Bean("springbootQueue")
    public Queue SpringbootQueue()
    {
        return new Queue("springbootQueue");
    }
    /*
    绑定交换机和队列
    注意不同的交换机有不同的BindingBuilder的bind方法
     */
    @Bean
    public Binding bind(@Qualifier("springbootExchange")Exchange exchange,@Qualifier("springbootQueue")Queue queue)
    {
       /* //广播
        Binding ss = BindingBuilder.bind(queue).to(new FanoutExchange("ss"));
        //适配器
        Binding aa = BindingBuilder.bind(queue).to(new TopicExchange("aa")).with("bind.#");
        //直接
        BindingBuilder.bind(queue).to(exchange).with("bind");
        //默认
        Exchange aa1 = new DirectExchange("aa");
        Binding bind = BindingBuilder.bind(queue).to(aa1).with("bind").noargs();*/
        return  BindingBuilder.bind(queue).to(exchange).with("bind").noargs();
    }
}
​

3.2实战

和spring没什么区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值