案例场景为:用户注册成功后,自动触发「发送欢迎短信」和「初始化用户积分」两个监听事件,体现事件机制的解耦特性(注册逻辑和后续操作完全分离)。

一、环境准备

只需引入Spring Boot核心依赖即可,Maven坐标:

<!-- Spring Boot父工程 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version> <!-- 推荐稳定版,3.x版本用法一致 -->
    <relativePath/>
</parent>

<!-- 核心依赖 -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
</dependencies>

二、完整入门案例代码

整个案例分4个核心部分:自定义事件事件监听器事件发布者测试启动,代码结构清晰,直接复制即可运行。

1. 定义用户实体(基础数据载体)

简单封装用户注册信息,非事件核心,仅为传递数据:

package com.example.springeventdemo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 用户实体
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    // 用户ID
    private Long id;
    // 用户名
    private String username;
    // 手机号(用于发送短信)
    private String phone;
}

(注:使用lombok简化代码,若未引入,手动写get/set即可;lombok依赖可自行添加,不影响事件核心逻辑)

2. 自定义事件(继承ApplicationEvent)

Spring所有自定义事件都需要继承ApplicationEvent(Spring 4.2+也可使用注解@EventListener,无需继承,后续补充),用于封装事件的触发数据(如注册的用户信息)。

package com.example.springeventdemo.event;

import com.example.springeventdemo.entity.User;
import org.springframework.context.ApplicationEvent;

/**
 * 自定义事件:用户注册成功事件
 * 继承ApplicationEvent,作为事件载体传递用户数据
 */
public class UserRegisterEvent extends ApplicationEvent {

    // 事件携带的核心数据:注册的用户信息
    private User user;

    /**
     * 构造方法:必须调用父类的构造方法(传入事件源)
     * @param source 事件源(触发事件的对象,可传null/当前类/业务类)
     * @param user 注册的用户信息
     */
    public UserRegisterEvent(Object source, User user) {
        super(source);
        this.user = user;
    }

    // GET方法(供监听器获取事件数据)
    public User getUser() {
        return user;
    }
}

核心点:构造方法必须调用父类super(source)source是事件源,用于标识哪个对象触发了事件,可灵活传值。

3. 定义事件监听器(两种常用方式)

监听器是订阅事件的组件,当事件被发布后,Spring会自动执行监听器的处理方法。推荐两种入门方式,任选其一即可(方式2更简洁)。

方式1:实现ApplicationListener接口(传统方式)

实现ApplicationListener<自定义事件>接口,重写onApplicationEvent方法,泛型指定要监听的事件(精准监听)。

package com.example.springeventdemo.listener;

import com.example.springeventdemo.entity.User;
import com.example.springeventdemo.event.UserRegisterEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * 监听器1:实现接口方式 - 监听用户注册事件,发送欢迎短信
 * 必须加@Component,让Spring容器管理,否则无法被扫描到
 */
@Component
public class SendSmsListener implements ApplicationListener<UserRegisterEvent> {

    /**
     * 事件触发时执行的方法
     * @param event 触发的用户注册事件(包含用户数据)
     */
    @Override
    public void onApplicationEvent(UserRegisterEvent event) {
        User user = event.getUser();
        // 模拟发送欢迎短信的业务逻辑
        System.out.println("【短信监听器】用户" + user.getUsername() + "注册成功,已发送欢迎短信至:" + user.getPhone());
    }
}
方式2:使用@EventListener注解(推荐,简洁)

Spring 4.2+推出的注解方式,无需实现接口,只需在方法上标注@EventListener并指定监听的事件,方法参数为事件对象即可,更灵活。

package com.example.springeventdemo.listener;

import com.example.springeventdemo.entity.User;
import com.example.springeventdemo.event.UserRegisterEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

/**
 * 监听器2:注解方式 - 监听用户注册事件,初始化用户积分
 * 必须加@Component,让Spring容器管理
 */
@Component
public class InitScoreListener {

    /**
     * 事件处理方法:@EventListener指定监听的事件类型
     * 方法参数直接传事件对象,Spring会自动注入
     */
    @EventListener(UserRegisterEvent.class)
    public void onUserRegister(UserRegisterEvent event) {
        User user = event.getUser();
        // 模拟初始化用户积分的业务逻辑
        int initScore = 100; // 注册送100积分
        System.out.println("【积分监听器】用户" + user.getUsername() + "注册成功,已初始化积分:" + initScore + "分");
    }
}

核心点:监听器类必须加@Component(或@Service/@Repository),让Spring容器扫描并管理,否则无法触发。

4. 定义事件发布者(注入ApplicationEventPublisher)

要发布事件,需要通过**ApplicationEventPublisher**接口的publishEvent方法,Spring容器会自动注入该接口的实现类,直接在业务类中注入使用即可。

这里模拟用户注册的业务服务,注册成功后发布事件:

package com.example.springeventdemo.service;

import com.example.springeventdemo.entity.User;
import com.example.springeventdemo.event.UserRegisterEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

/**
 * 用户业务服务:模拟用户注册,注册成功后发布事件
 */
@Service
public class UserService {

    /**
     * 注入事件发布器:Spring自动提供实现类,直接使用即可
     */
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 模拟用户注册方法
     * @param user 用户信息
     */
    public void register(User user) {
        // 1. 核心业务:模拟用户注册(如插入数据库)
        System.out.println("【用户服务】用户" + user.getUsername() + "注册成功,核心业务执行完成");

        // 2. 注册成功后,发布「用户注册事件」
        // 第一个参数:事件源(这里传当前业务类UserService),第二个参数:用户数据
        eventPublisher.publishEvent(new UserRegisterEvent(this, user));
    }
}

核心点:publishEvent方法传入自定义事件对象,Spring会自动将事件派发给所有监听该事件的监听器。

5. 启动类+测试(运行案例)

编写Spring Boot启动类,通过CommandLineRunner实现项目启动后自动执行测试代码,无需手动写测试类,更便捷:

package com.example.springeventdemo;

import com.example.springeventdemo.entity.User;
import com.example.springeventdemo.service.UserService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class SpringEventDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringEventDemoApplication.class, args);
    }

    /**
     * 项目启动后自动执行:测试用户注册+事件发布
     */
    @Bean
    public CommandLineRunner testEvent(UserService userService) {
        return args -> {
            // 模拟一个用户注册
            User user = new User(1L, "张三", "13800138000");
            // 调用注册方法,触发事件发布
            userService.register(user);
        };
    }
}

三、运行结果

启动项目后,控制台会按核心业务→监听器1→监听器2的顺序输出(监听器执行顺序可自定义,入门阶段默认即可):

【用户服务】用户张三注册成功,核心业务执行完成
【短信监听器】用户张三注册成功,已发送欢迎短信至:13800138000
【积分监听器】用户张三注册成功,已初始化积分:100分

从结果能清晰看到:用户注册的核心业务执行后,自动触发了两个监听器的逻辑,且注册逻辑和后续操作完全解耦(若后续要加「注册送优惠券」,只需新增一个监听器,无需修改UserService的注册代码)。

四、Spring Event核心知识点(入门必懂)

  1. 核心三要素

    • 事件(Event):继承ApplicationEvent,封装事件数据,是发布-订阅的载体;
    • 监听器(Listener):实现接口或加@EventListener,订阅并处理事件;
    • 发布者(Publisher):通过ApplicationEventPublisher.publishEvent发布事件。
  2. Spring的自动扫描
    监听器、发布者(业务类)必须被Spring容器管理(加@Component/@Service等),否则Spring无法扫描到,事件无法触发。

  3. 无继承的事件(Spring 4.2+)
    入门案例中事件继承了ApplicationEvent,其实4.2+后可无需继承,直接定义普通POJO作为事件,发布和监听方式完全一致,示例:

    // 普通POJO事件(无需继承)
    @Data
    public class UserRegisterSimpleEvent {
        private User user;
    }
    // 发布事件
    eventPublisher.publishEvent(new UserRegisterSimpleEvent(user));
    // 监听事件(注解方式)
    @EventListener(UserRegisterSimpleEvent.class)
    public void handleEvent(UserRegisterSimpleEvent event) { ... }
    
  4. 同步执行特性
    入门案例中事件是同步执行的:发布事件后,主线程会等待所有监听器执行完成,再继续后续逻辑。若需要异步执行,只需给监听器方法加@Async注解(需在启动类加@EnableAsync开启异步)。

五、扩展:异步执行事件(常用需求)

若希望监听器的逻辑不阻塞核心业务(比如发送短信可能耗时,不希望影响用户注册的响应速度),只需两步实现异步:

  1. 在Spring Boot启动类加@EnableAsync,开启异步功能:
    @SpringBootApplication
    @EnableAsync // 开启异步
    public class SpringEventDemoApplication { ... }
    
  2. 在监听器的处理方法上加@Async注解:
    // 短信监听器异步执行
    @Async
    @EventListener(UserRegisterEvent.class)
    public void onUserRegister(UserRegisterEvent event) { ... }
    

修改后运行,核心业务会先执行完成,监听器在子线程中执行,实现解耦+异步,提升接口响应效率。

总结

Spring Event入门的核心就是掌握三要素的定义和使用,关键要点:

  1. 自定义事件可继承ApplicationEvent(传统)或直接用普通POJO(4.2+推荐),用于传递事件数据;
  2. 监听器通过「实现接口」或「@EventListener注解」实现,必须被Spring容器管理;
  3. 事件发布通过注入ApplicationEventPublisher调用publishEvent方法,在业务触发点执行;
  4. 默认同步执行,加@EnableAsync+@Async可实现异步,解耦且不阻塞核心业务。

该机制适用于业务触发后需要执行后续非核心操作的场景(如注册后发消息、下单后扣库存、日志记录等),能有效降低代码耦合度,提升扩展性。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐