如何使用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实现异步消息

相关推荐
秋名RG几秒前
Java 核心特性一览
java·开发语言
霸道流氓气质5 分钟前
Spring AI 技术细节:RAG QuestionAnswerAdvisor 设计与实现
java·人工智能·spring
平头哥AI28 分钟前
Day 01 | go run 跑通第一个 Go 程序,go build 留下一个能拷走的 exe
开发语言·后端·golang
斑马13934 分钟前
Linux软件编程学习笔记(十二)——TCP并发服务器模型
java·服务器·网络
冬栈程序设计38 分钟前
Springboot宿舍管理系统【670099】 -附源码(开箱即用)
java·毕业设计·springboot·课程设计·程序设计·大作业
2601_962284501 小时前
北京Java全栈开发培训 Web前端开发 软件测试就业培训班
java·软件测试·web前端·全栈开发·就业培训
qiaosaifei1 小时前
JAVA老项目中有大量的类名_编译时报找不到符号错误
java·开发语言
聪明蛋子哟1 小时前
MCP协议深度落地:如何用Python/Java双语言实现统一的工具调用网关?
java·开发语言·python
文子越来越强1 小时前
【双因子认证】拦截注解@MFACheck 接入指南(其他微服务如何用)
java
ZGG0032 小时前
线程池详解:从 7 大参数到生产避坑
java·数据库·后端