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

相关推荐
2301_780789665 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
学长毕设6 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
滴滴答答哒7 小时前
ASP.NET Core + FaceRecognitionDotNet 人脸识别实战:DI 单例、特征向量持久化与 1:N 比对
后端·asp.net
步行cgn7 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川7 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵7 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程
秋天的怀念_David7 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Raas1008 小时前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品
niucloud-admin8 小时前
NIUCLOUD PHP SAAS上门家政使用文档:城市管理
java·前端·php
霸道流氓气质9 小时前
智能客服组件:分层意图识别、RAG Advisor 与人工转接状态机的 Vue3 + Spring AI 生产级实战
java·人工智能·spring