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的方式,則簡潔很多,在日常工作中,推薦使用這種方式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章