RabbitMQ-java中的操作

本文详细介绍了如何在普通Maven工程中使用RabbitMQ实现工作队列模式和发布订阅模式,包括依赖配置、消息发送与接收流程、消息应答与持久化策略,以及Spring Boot集成RabbitMQ的配置和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

普通maven工程中

工作队列模式

  1. pom.xml
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>4.0.3</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>
  1. 消息发送方
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();

connectionFactory.setHost("192.168.199.132");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");

//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机相当于一个独立的mq
connectionFactory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try{
    //建立新连接
    connection = connectionFactory.newConnection();
    //创建会话通道,生产者和mq服务所有通信都在channel通道中完成
    channel = connection.createChannel();
    //监听队列
    // 声明队列,交换机默认
    //queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
    /**
     * String queue 队列名称
     * boolean durable 是否持久化,即mq重启是否还在
     * boolean exclusive 是否独占连接,即连接关闭时队列自动删除,true是删除
     * boolean autoDelete 是否自动删除,队列不再使用时删除,与exclusive都设为true就可以实现临时队列
     * Map<String, Object> arguments 参数,可以设置一个队列的扩展参数,如存活时间
     */
    String queue = "Hello World !";
    channel.queueDeclare(queue,true,false,false,null);

    //发送消息
    //参数:basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body)
    /**
     * String exchange 交换机,不指定将使用默认的
     * String routingKey 路由key,交换机根据路由key来转发到指定的队列
     *      如果使用默认交换机,routingKey设置为队列名称
     *  props 消息的属性
     *  body 消息内容
     */
    String message = "hello RabbitMQ !";
    channel.basicPublish("",queue,null,message.getBytes());
    System.out.println("send");
}catch(Exception e){
    e.printStackTrace();
}finally {
    channel.close();
    connection.close();
}
  1. 消息接收方
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();

connectionFactory.setHost("192.168.199.132");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");

//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机相当于一个独立的mq
connectionFactory.setVirtualHost("/");

Connection connection = null;

//建立新连接
connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
Channel channel = connection.createChannel();

//监听队列
// 声明队列,交换机默认
//queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
/**
 * String queue 队列名称
 * boolean durable 是否持久化,即mq重启是否还在
 * boolean exclusive 是否独占连接,即连接关闭时队列自动删除,true是删除
 * boolean autoDelete 是否自动删除,队列不再使用时删除,与exclusive都设为true就可以实现临时队列
 * Map<String, Object> arguments 参数,可以设置一个队列的扩展参数,如存活时间
 */
String queue = "Hello World !";
channel.queueDeclare(queue,true,false,false,null);

//开始不同
// 实现消费方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
    /**
     *
     * @param consumerTag  消费者标签,用来标识消费者,可在监听队列时设置channel.basicConsume
     * @param envelope  信封,通过envelope获取
     * @param properties 消息属性
     * @param body 消息内容
     * @throws IOException
     */
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
       //交换机
        String exchange = envelope.getExchange();
        //消息id,mq在channel中用来表示消息的id,可用于确认消息已接收
        long deliveryTag = envelope.getDeliveryTag();
        //消息内容
        String message = new String(body, "utf-8");
        System.out.println(message);
    }
};

//basicConsume(String queue, boolean autoAck, Consumer callback)
/**
 * String queue 队列名称
 * boolean autoAck 自动回复,当消费者接收到消息后要告诉mq消息已接收,设置true表示自动回复mq,false要编程实现回复
 * Consumer callback 消费方法,当消费者接受到消息要执行的方法
 */
//监听队列
channel.basicConsume(queue,true,defaultConsumer);

Publish模式

  1. 服务提供者
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();

connectionFactory.setHost("192.168.199.132");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");

//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机相当于一个独立的mq
connectionFactory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try{
    //建立新连接
    connection = connectionFactory.newConnection();
    //创建会话通道,生产者和mq服务所有通信都在channel通道中完成
    channel = connection.createChannel();

    // 声明两个队列,交换机默认

    channel.queueDeclare(QUEUE_INFORM_EMAIL,true,false,false,null);
    channel.queueDeclare(QUEUE_INFORM_SMS,true,false,false,null);

    //声明交换机
    //exchangeDeclare(String exchange, String type)
    /**
     * String exchange 名称
     * String type 类型 BuiltinExchangeType.TYPE
     *      1. fanout : 对应 publish/subscribe
     *      2. direct :  Routing
     *      3. topic :  Topics
     *      4. headers : headers
     */
    channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);

    // 交换机和队列进行绑定
    //queueBind(String queue, String exchange, String routingKey)
    /**
     * String queue : 队列名称
     * String exchange : 交换机名称
     * String routingKey :路由key,交换机根据路由key将消息转发到指定的队列中,在发布订阅中协调为空字符串
     */
    channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_FANOUT_INFORM,"");
    channel.queueBind(QUEUE_INFORM_SMS,EXCHANGE_FANOUT_INFORM,"");
    //发送消息
    for (int i = 0; i < 5; i++) {
        String message = "send inform message";
        /**
         * String exchange 交换机,不指定将使用默认的,""
         * String routingKey 路由key,交换机根据路由key来将校级转发到指定的队列
         *      如果使用默认交换机,routingKey设置为队列名称
         *  props 消息的属性
         *  body 消息内容
         */
        channel.basicPublish(EXCHANGE_FANOUT_INFORM,"",null,message.getBytes());
        System.out.println("send");
    }
}catch(Exception e){
    e.printStackTrace();
}finally {
    channel.close();
    connection.close();
}
  1. 服务消费者
//队列名称
private static String QUEUE_INFORM_EMAIL = "queue_inform_email";
//private static String QUEUE_INFORM_SMS = "queue_inform_sms"; 可作为另一个类
private static String EXCHANGE_FANOUT_INFORM = "exchange_fanout_inform";
public static void main(String[] args) throws Exception{
    //通过连接工厂创建新的连接和mq建立连接
    ConnectionFactory connectionFactory = new ConnectionFactory();

    connectionFactory.setHost("192.168.199.132");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");

    //设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机相当于一个独立的mq
    connectionFactory.setVirtualHost("/");

    Connection connection = null;

    //建立新连接
    connection = connectionFactory.newConnection();
    //创建会话通道,生产者和mq服务所有通信都在channel通道中完成
    Channel channel = connection.createChannel();

    //监听队列
    // 声明队列,交换机默认
    //queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
    /**
     * String queue 队列名称
     * boolean durable 是否持久化,即mq重启是否还在
     * boolean exclusive 是否独占连接,即连接关闭时队列自动删除,true是删除
     * boolean autoDelete 是否自动删除,队列不再使用时删除,与exclusive都设为true就可以实现临时队列
     * Map<String, Object> arguments 参数,可以设置一个队列的扩展参数,如存活时间
     */
    channel.queueDeclare(QUEUE_INFORM_EMAIL,true,false,false,null);
    /**
     * String queue : 队列名称
     * String exchange : 通道名称
     * String routingKey :路由key,交换机根据路由key将消息转发到指定的队列中,在发布订阅中协调为空字符串
     */
    channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_FANOUT_INFORM,"");

    //开始不同
    // 实现消费方法
    DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
        /**
         *
         * @param consumerTag  消费者标签,用来标识消费者,可在监听队列时设置channel.basicConsume
         * @param envelope  信封,通过envelope获取
         * @param properties 消息属性
         * @param body 消息内容
         * @throws IOException
         */
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            //交换机
            String exchange = envelope.getExchange();
            //消息id,mq在channel中用来表示消息的id,可用于确认消息已接收
            long deliveryTag = envelope.getDeliveryTag();
            //消息内容
            String message = new String(body, "utf-8");
            System.out.println(message);
        }
    };

    //basicConsume(String queue, boolean autoAck, Consumer callback)
    /**
     * String queue 队列名称
     * boolean autoAck 自动回复,当消费者接收到消息后要告诉mq消息已接收,设置true表示自动回复mq,false要编程实现回复
     * Consumer callback 消费方法,当消费者接受到消息要执行的方法
     */
    //监听队列
    channel.basicConsume(QUEUE_INFORM_EMAIL,true,defaultConsumer);
}

消息应答与消息持久化

  1. 接收方消息应答
    消息应答确认

NONE:自动确认
AUTO : 看情况确认
manual :手动确认
在这里插入图片描述

  1. 生产方-事务机制
channel.txSelect(); //开始
channel.txCommit(); // 提交
channel.txRollback(); // 回滚
  1. 生产方-Confirm模式
    在这里插入图片描述

Confirm模式最大的好处在于他是异步
开启:channel.confirmSelect()

Publisher Confirms
编程模式:

  1. 普通,发一条:waitForConfirms()
  2. 批量,发一批:waitForConfirms()
  3. 异步:提供一个回调方法

SpringBoot中

配置

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

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
</dependency>
  1. application.yml
server:
  port: 44000
spring:
  application:
    name: test-rabbitmq
  rabbitmq:
    host: 192.168.199.132
    port: 5672
    username: guest
    password: guest
    virtual-host: /
  1. 自定义RabbitmqConfig
@Configuration
public class RabbitmqConfig {

    // 声明交换机
    @Bean("direct")
    public DirectExchange directExchange(){
        //交换机名字,是否持久化,是否自动删除
        return new DirectExchange("direct",false,false);
    }

    //声明队列
    @Bean("sms")
    public Queue queSms(){
        //队列名,是否持久化
        return new Queue("sms",false);
    }

    @Bean("email")
    public Queue queEmail(){
        return new Queue("email",false);
    }

    //绑定交换机和队列
    @Bean
    Binding bindingSms(Queue sms,DirectExchange directExchange){
        // 队列, 交换机 , routingKey
        return BindingBuilder.bind(sms).to(directExchange).with("");
    }

    @Bean
    Binding bindingEmail(Queue email,DirectExchange directExchange){
        return BindingBuilder.bind(email).to(directExchange).with("");
    }
}

发送方

@Autowired
RabbitTemplate rabbitTemplate;

//使用rabbitTemplate发送消息
@Test
void contextLoads() {
//交换机,routingKey,信息
    rabbitTemplate.convertAndSend("direct",""," send boot");
}

接收方

启动时就会自动接收

import org.springframework.amqp.core.Message;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class ReceiveHandler {

    @RabbitListener(queues = {"email"})
    public void send_email(String msg, Message message, Channel channel){
        System.out.println("Get message is email-" + msg);
    }

    @RabbitListener(queues = {"sms"})
    public void send_sms(String msg, Message message, Channel channel){
        System.out.println("Get message is sms-" + msg);
    }
}

大佬配置RabbitMQ默认配置

import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.util.HashMap;

/**
 * @Author: XF-DD
 * @Date: 20/05/19 23:04
 * 通用化 Rabbitmq 的配置
 */
@Configuration
public class RabbitmqConfig {

    private final static Logger logger = LoggerFactory.getLogger(RabbitmqConfig.class);

    @Autowired
    private Environment environment;

    //建立通道连接,缓存连接工厂
    @Autowired
    private CachingConnectionFactory connectionFactory;

    //消费者所在容器工厂
    @Autowired
    private SimpleRabbitListenerContainerFactoryConfigurer factoryConfigurer;

    /**
     * 单一消费者
     *
     * @return
     */
    @Bean(name = "singleListenerContainer")
    public SimpleRabbitListenerContainerFactory listenerContainer() {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(new Jackson2JsonMessageConverter()); //消息传输格式
        factory.setConcurrentConsumers(1);
        factory.setMaxConcurrentConsumers(1);
        factory.setPrefetchCount(1);
        factory.setTxSize(1);
        return factory;
    }

    /**
     * 多个消费者
     *
     * @return
     */
    @Bean(name = "multiListenerContainer")
    public SimpleRabbitListenerContainerFactory multiListenerContainer() {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factoryConfigurer.configure(factory, connectionFactory);
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        //确认消费模式-NONE
        factory.setAcknowledgeMode(AcknowledgeMode.NONE);
        //多少个消费者
        factory.setConcurrentConsumers(environment.getProperty("spring.rabbitmq.listener.simple.concurrency", int.class));
        //最多多少个消费者
        factory.setMaxConcurrentConsumers(environment.getProperty("spring.rabbitmq.listener.simple.max-concurrency", int.class));
        //每个消费者预拉取数量
        factory.setPrefetchCount(environment.getProperty("spring.rabbitmq.listener.simple.prefetch", int.class));
        return factory;
    }

    @Bean
    public RabbitTemplate rabbitTemplate() {
        //必须要设置,发送确认
        connectionFactory.setPublisherConfirms(true);
        connectionFactory.setPublisherReturns(true);

        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * @param correlationData 唯一标识,有了这个唯一标识,我们就知道可以确认(失败)哪一条消息了
             * @param ack
             * @param cause
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                logger.info("消息发送成功:correlationData({}),ack({}),cause({})", correlationData, ack, cause);
            }
        });
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                logger.warn("消息丢失:exchange({}),route({}),replyCode({}),replyText({}),message:{}", exchange, routingKey, replyCode, replyText, message);
            }
        });
        return rabbitTemplate;
    }
}
实现 Spring Boot、RabbitMQ 和 WebSocket 结合的方式主要有以下几个步骤: 1. 创建 Spring Boot 项目,添加 RabbitMQ 和 WebSocket 的相关依赖。 2. 创建 RabbitMQ 队列和交换机,用于发送消息。 3. 创建 WebSocket 配置类,配置 WebSocket 的相关参数。 4. 创建 WebSocket 处理器类,处理 WebSocket 的连接、消息发送等操作。 5. 创建 RabbitMQ 消息监听器类,监听 RabbitMQ 队列中的消息,将消息发送给 WebSocket 处理器。 下面是具体的实现步骤: 1. 创建 Spring Boot 项目,添加 RabbitMQ 和 WebSocket 的相关依赖。 在 pom.xml 中添加以下依赖: ```xml <dependencies> <!-- RabbitMQ 相关依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <!-- WebSocket 相关依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> </dependencies> ``` 2. 创建 RabbitMQ 队列和交换机,用于发送消息。 在 RabbitMQ 中创建一个交换机和一个队列,然后将队列绑定到交换机上。这里我们使用 RabbitMQ 的默认交换机和队列。 ```java @Configuration public class RabbitMQConfig { @Bean public Queue queue() { return new Queue("websocket"); } @Bean public DirectExchange exchange() { return new DirectExchange(""); } @Bean public Binding binding(Queue queue, DirectExchange exchange) { return BindingBuilder.bind(queue).to(exchange).with("websocket"); } } ``` 3. 创建 WebSocket 配置类,配置 WebSocket 的相关参数。 ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); registry.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/websocket").setAllowedOrigins("*").withSockJS(); } } ``` 4. 创建 WebSocket 处理器类,处理 WebSocket 的连接、消息发送等操作。 ```java @Component public class WebSocketHandler implements WebSocketHandler { private static final Logger logger = LoggerFactory.getLogger(WebSocketHandler.class); private SimpMessagingTemplate messagingTemplate; @Autowired public WebSocketHandler(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { logger.info("WebSocket connected: {}", session.getId()); } @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { logger.info("WebSocket received message: {}", message.getPayload()); } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { logger.error("WebSocket transport error: {}", exception.getMessage()); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { logger.info("WebSocket disconnected: {}", session.getId()); } @Override public boolean supportsPartialMessages() { return false; } public void sendMessage(String message) { messagingTemplate.convertAndSend("/topic/messages", message); } } ``` 5. 创建 RabbitMQ 消息监听器类,监听 RabbitMQ 队列中的消息,将消息发送给 WebSocket 处理器。 ```java @Component public class RabbitMQListener { private static final Logger logger = LoggerFactory.getLogger(RabbitMQListener.class); private WebSocketHandler webSocketHandler; @Autowired public RabbitMQListener(WebSocketHandler webSocketHandler) { this.webSocketHandler = webSocketHandler; } @RabbitListener(queues = "websocket") public void handleMessage(String message) { logger.info("RabbitMQ received message: {}", message); webSocketHandler.sendMessage(message); } } ``` 至此,Spring Boot、RabbitMQ 和 WebSocket 结合的实现就完成了。我们可以通过 RabbitMQ 发送消息到队列,然后监听器会将消息发送给 WebSocket 处理器,处理器再将消息发送给 WebSocket 客户端。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值