Spring Boot下使用RabbitMQ

概述


本文主要一下在JAVA 中使用Rabbit MQ的三种方式:

  • 原始方式
  • 结合Spring
  • 结合Spring Boot

下面将使用逐步演进的方式来讲解JAVA下如何使用Rabbit MQ发布订阅模式


最原始的方式


本文的DEMO是用Window版本的Rabbit MQ的,具体的安装方式,可以参考:

我们先将Rabbit MQ Client 引入进来。

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

建立一个MsgSender类来实现消息发送。

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

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class MsgSender {
    private final static String EXCHANGE_NAME = "hello_fanout_1";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        //发布订阅者模式
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);

        String message = "hello world.";
        channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
        channel.close();
        connection.close();
    }
}

直接执行后,可以在Rabbit MQ的管理界面看到,hello_fanout_1这个exchange已经成功创建了。
在这里插入图片描述

目前hello world.这条消息已经存储在hello_fanout_1这个exchange里了,我们只需要编写一个消费者,设置一个队列且绑定上去,就可以收到消息了。

import com.rabbitmq.client.*;

import java.io.IOException;

public class MsgReceiver {
    private final static String EXCHANGE_NAME = "hello_fanout_1";
    private final static String QUEUE_NAME = "hello_queue_1";

    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)  throws IOException {
                String message = new String(body, "UTF-8");
                System.out.println("receive message:"+message);
            }
        };

        channel.basicConsume(QUEUE_NAME, true, consumer);
    }
}

执行完MsgReceivermain方法后,控制台输出如下:

receive message:hello world.

到此一个简单的发布订阅模式就写完了。下面使用Spring集合Rabbit MQ的方式,重构一下代码。


Spring结合Rabbit MQ


生产者Rabbit配置

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MsgProduceRabbitConfig {
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setAddresses("127.0.0.1:5672");
        return factory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }
}

RabbitAdmin 主要用于声明队列和交换器,而RabbitTemplate用于发送消息。为了方便测试,引入Junit

 <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>5.0.8.RELEASE</version>
          <scope>test</scope>
 </dependency>
 <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
 </dependency>

编写消息发送测试类:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={MsgProduceRabbitConfig.class})
public class MsgSendTest {
    private final static String EXCHANGE_NAME = "hello_fanout_1";
    private final static String QUEUE_NAME = "hello_queue_1";

    @Autowired
    private RabbitAdmin rabbitAdmin;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSend() {
        FanoutExchange fanoutExchange = new FanoutExchange(EXCHANGE_NAME, false, false);
        Queue queue = new Queue(QUEUE_NAME, false);
        rabbitAdmin.declareExchange(fanoutExchange);
        rabbitAdmin.declareQueue(queue);
        rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(fanoutExchange));

        Message message = new Message("hello world.".getBytes(), new MessageProperties());
        rabbitTemplate.send(EXCHANGE_NAME, "", message);
    }
}

消息消费者配置类。

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MsgConsumerRabbitConfig {
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setAddresses("127.0.0.1:5672");
        return factory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }

    @Bean
    public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory){
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.setQueueNames("hello_queue_1");
        container.setMessageListener(msgListener());
        return container;
    }

    @Bean
    public MsgListener msgListener() {
        return new MsgListener();
    }

消费者端需要配置一个SimpleMessageListenerContainer类以及一个消息消费者MsgListener,并将MsgListener加入到SimpleMessageListenerContainer里去。

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;

public class MsgListener implements MessageListener{
    @Override
    public void onMessage(Message message) {
        System.out.println("receive message:" + new String(message.getBody()));
    }
}

测试类如下:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={MsgConsumerRabbitConfig.class})
public class MsgConsumerTest {
    @Test
    public void testConsumer() {
    }
}

testConsumer方法空实现就行,直接执行一下,也是输出了

receive message:hello world.


Spring Boot 整合Rabbit MQ


先引入依赖:

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

使用的Spring Boot的版本是:

2.0.4.RELEASE

由于Spring Boot跑单元测试的时候,也需要一个Spring Boot Application,因此我们手动构造一个,并且加入@EnableRabbit注解,启动监听器。

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;

/**
 * 由于是基于spring boot test组件进行单元测试,需要构建一个TestApplication上下文
 */
@SpringBootApplication
@EnableRabbit
public class TestApplication {

    public static void main(String[] args){
        SpringApplicationBuilder builder = new SpringApplicationBuilder();
        builder.environment(new StandardEnvironment());
        builder.sources(TestApplication.class);
        builder.main(TestApplication.class);
        builder.run(args);
    }
}

直接编写发送消息的测试类:

import org.junit.Test;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class SpringBootMqSendTest{
    private final static String EXCHANGE_NAME = "hello_fanout_1";
    private final static String QUEUE_NAME = "hello_queue_1";

    @Autowired
    private RabbitAdmin rabbitAdmin;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSend(){
        FanoutExchange fanoutExchange = new FanoutExchange(EXCHANGE_NAME, false, false);
        Queue queue = new Queue(QUEUE_NAME, false);
        rabbitAdmin.declareExchange(fanoutExchange);
        rabbitAdmin.declareQueue(queue);
        rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(fanoutExchange));

        Message message = new Message("hello world.".getBytes(), new MessageProperties());
        rabbitTemplate.send(EXCHANGE_NAME, "", message);
    }
}

编写消息消费者:

mport org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class SpringBootMsqConsumer {
    @RabbitListener(queues = "hello_queue_1")
    public void receive(Message message) {
        System.out.println("receive message:" + new String(message.getBody()));
    }
}

编写消息测试类:

import org.junit.Test;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class SpringBootMqConsumerTest {
    @Autowired
    private SpringBootMsqConsumer springBootMsqConsumer;

    @Test
    public void testConsumer(){
    }
}

执行testConsumer方法后,控制台也是输出:

receive message:hello world.


总结


有上面的内容可以得知,Spring 整合Rabbit MQ的方式,使用起来也不是很方便,需要蛮多配置类的,而Spring Boot整合Rabbit MQ的方式,则简洁很多,在日常工作中,推荐使用这种方式。

猜你喜欢

转载自blog.csdn.net/linsongbin1/article/details/100186416