概述
本文主要一下在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
的方式,则简洁很多,在日常工作中,推荐使用这种方式。