概述
本文主要一下在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);
}
}
執行完MsgReceiver
的main
方法後,控制檯輸出如下:
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
的方式,則簡潔很多,在日常工作中,推薦使用這種方式。