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

相关推荐
四念处茫茫5 小时前
Rust:与JSON、TOML等格式的集成
java·rust·json
摸鱼仙人~5 小时前
一文深入学习Java动态代理-JDK动态代理和CGLIB
java·开发语言·学习
东百牧码人5 小时前
如何避免NullReferenceException
后端
微知语5 小时前
Cell 与 RefCell:Rust 内部可变性的双生子解析
java·前端·rust
用户68545375977695 小时前
电商防止超卖终极方案:让库存管理滴水不漏!🎯
后端
xiaojimao16 小时前
Django在服务端的部署(无废话)
后端·python·django
雨过天晴而后无语6 小时前
Windchill10+html使用Lightbox轻量化wizard的配置
java·前端·html
Yeats_Liao6 小时前
Go Web 编程快速入门 12 - 微服务架构:服务发现、负载均衡与分布式系统
前端·后端·架构·golang
Yeniden6 小时前
设计模式>原型模式大白话讲解:就像复印机,拿个原件一复印,就得到一模一样的新东西
java·设计模式·原型模式·1024程序员节