如何使用Spring Context实现消息队列

说明:MQ 组件有很多,有 Kafka、Rabbit MQ、Rabbit MQ,如果不想引入这些组件,还能依靠 Redis 作为 MQ 组件,另外,如果不像引入 MQ 组件,仅想实现某些方法的异步操作,还能使用 Spring Boot 中自带的 @Async 注解。

相关博客

本文介绍如何使用 Spring Context 实现消息队列

实现

定义一个消息对象,如下:

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 消息对象
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyMessage {

    private String messageId;

    private String message;
}

消息生产者,使用 ApplicationContext 推送消息

java 复制代码
import com.hezy.service.mq.message.MyMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 消息生产者
 */
@Slf4j
@Component
public class MyProducer {

    @Resource
    private ApplicationContext applicationContext;

    public void sendMyMessage(String messageId, String message) {
        MyMessage myMessage = new MyMessage(messageId, message);
        applicationContext.publishEvent(myMessage);
    }
}

消息消费者,接收消息,并转发到指定实现类执行

java 复制代码
import com.hezy.service.DemoService;
import com.hezy.service.mq.message.MyMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 消息消费着
 */
@Slf4j
@Component
public class MyConsumer {

    @Resource
    private DemoService demoService;

    @EventListener
    @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
    public void onMessage(MyMessage message) {
        log.info("[onMessage][消息内容({})]", message);
        demoService.doMyMessage(message);
    }
}

消费方法

java 复制代码
import com.hezy.service.mq.message.MyMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class DemoServiceImpl implements DemoService {

    /**
     * 消息消费方法
     *
     * @param message 消息
     */
    @Override
    public void doMyMessage(MyMessage message) {
        log.info("收到消息:{}, 去做一些事情", message);
    }
}

写一个接口,推送消息

java 复制代码
import com.hezy.service.mq.message.MyMessage;
import com.hezy.service.mq.producer.MyProducer;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@RestController
@RequestMapping("/demo")
public class DemoController {

    @Resource
    private MyProducer myProducer;

    @PostMapping("/put")
    private void test(@RequestBody MyMessage myMessage) {
        myProducer.sendMyMessage(myMessage.getMessageId(), myMessage.getMessage());
    }
}

以上代码,pom.xml 如下,功能实现仅使用了 Spring Boot 框架

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.12</version>
        <relativePath/>
    </parent>

    <groupId>com.hezy</groupId>
    <artifactId>spring_context_demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

启动,调用该接口

控制台可见消息被消费

另外

推送消息是异步操作,如下,在推送消息后线程休眠10秒,消息也会在接口返回结果之前被消费。

java 复制代码
    @PostMapping("/put")
    private void test(@RequestBody MyMessage myMessage) throws InterruptedException {
        myProducer.sendMyMessage(myMessage.getMessageId(), myMessage.getMessage());

        Thread.sleep(10000L);

        System.out.println("返回结果");
    }

消息推送给消费者,是通过消息对象来识别的,只要消息消费者的参数是消息对象,就能接收到该消息。

如果定义了多个消费者,参数是同一个消息对象,这些消费者都能接收到该消息,是广播的方式,如下:

总结

本文介绍了如何使用Spring Context实现异步消息

相关推荐
砍材农夫1 小时前
使用jstack排查死锁,面试考点
java
小码哥_常7 小时前
Spring Boot 牵手Spring AI,玩转DeepSeek大模型
后端
0xDevNull7 小时前
Java反射机制深度解析:从原理到实战
java·开发语言·后端
华洛7 小时前
我用AI做了一个48秒的真人精品漫剧,不难也不贵
前端·javascript·后端
华科易迅7 小时前
MybatisPlus增删改查操作
android·java·数据库
AugustRed7 小时前
基于现有的 Controller 接口 API 暴露 MCP
spring·mcp
WZTTMoon7 小时前
Spring Boot 中Servlet、Filter、Listener 四种注册方式全解析
spring boot·后端·servlet
standovon8 小时前
Spring Boot整合Redisson的两种方式
java·spring boot·后端
Cosolar8 小时前
LlamaIndex RAG 本地部署+API服务,快速搭建一个知识库检索助手
后端·openai·ai编程
IAUTOMOBILE8 小时前
Python 流程控制与函数定义:从调试现场到工程实践
java·前端·python