一、基本概况
1、什么是SpringBoot自定义事件
Spring Boot自定义事件是Spring框架中事件处理机制的一种扩展,它允许开发者在Spring Boot应用程序中定义、发布和监听自己的事件。这些事件可以用于在应用程序的不同组件之间进行通信,实现解耦和异步处理。通过自定义事件,开发者可以更加灵活地处理业务逻辑,提高系统的可扩展性和可维护性。
自定义事件通常继承自Spring的ApplicationEvent
类,并包含与事件相关的数据。开发者可以定义事件监听器来监听这些事件,并在事件发生时执行相应的逻辑。事件监听器可以通过实现ApplicationListener
接口或使用@EventListener
注解来创建。当事件被发布时,Spring容器会负责调用所有注册了对该事件感兴趣的监听器。
因此,Spring Boot自定义事件提供了一种强大的机制,允许开发者在不直接依赖其他组件的情况下进行通信和协作,从而实现更加松耦合和可扩展的系统设计。
2、SpringBoot自定义事件是主要作用
Spring Boot自定义事件在软件开发中起着非常重要的作用,主要体现在以下几个方面:
-
解耦:自定义事件允许应用程序的不同部分在不需要直接相互了解的情况下进行通信。这有助于降低模块间的耦合度,使得代码更加清晰、可维护,并方便扩展。
-
异步处理:通过事件机制,可以将某些操作异步化,提高系统的响应性能。例如,在用户注册成功后发送欢迎邮件或短信,这些操作可以通过事件监听器异步执行,不会阻塞主线程。
-
业务逻辑灵活性:自定义事件提供了一种灵活的方式来处理业务逻辑。通过定义不同的事件和监听器,可以轻松地添加、修改或删除业务逻辑,而无需修改与之无关的代码。
-
系统通知:当系统中发生重要事件时,可以使用自定义事件来通知其他部分。例如,当数据库中的某个表发生更改时,可以发布一个事件来通知其他服务或组件进行相应的处理。
-
可扩展性:由于自定义事件的解耦特性,它们使得系统更加容易扩展。新的功能或模块可以通过监听特定的事件来集成到现有系统中,而无需对现有代码进行大量修改。
-
日志记录和审计:自定义事件也可用于记录系统中发生的重要操作或事件,以便进行日志记录和审计。这对于系统的安全性和可追溯性非常重要。
-
状态管理:在某些场景下,自定义事件可用于管理系统的状态。例如,当某个长时间运行的任务完成时,可以发布一个事件来更新系统的状态或触发其他相关操作。
3、SpringBoot自定义事件相关核心类
在Spring Boot中,自定义事件处理涉及的核心类主要包括以下几个:
-
ApplicationEvent:这是所有Spring事件类的基类。自定义事件需要继承这个类,并可以在其中添加自己的属性和方法。
-
ApplicationEventPublisher:事件发布者接口,提供了
publishEvent
方法来发布事件。通常你会注入这个接口的实例来发布自定义事件。 -
ApplicationListener:事件监听器接口,需要实现这个接口并提供要监听的事件类型。当指定类型的事件被发布时,监听器的
onApplicationEvent
方法会被调用。 -
EventListener:这是一个注解,用于简化事件监听器的创建。你可以将这个注解添加到任何方法上,使其成为指定类型事件的监听器。
-
ConfigurableApplicationContext:这是Spring应用上下文的接口,它扩展了
ApplicationContext
接口并添加了生命周期管理和其他功能。ApplicationEventPublisher
通常是通过这个接口的实现类(如AnnotationConfigApplicationContext
)来获取的。 -
TransactionalEventListener:事务事件监听,可监听事务提交前、提交后、事务回滚、事务完成(成功或失败)
在实际开发中,你通常不会直接使用ConfigurableApplicationContext
,而是通过注入ApplicationEventPublisher
来发布事件,并通过实现ApplicationListener
接口或使用@EventListener
注解来创建事件监听器。这些核心类提供了构建自定义事件处理机制所需的基本构建块。
此外,还有一些与事件处理相关的支持类,如EventListenerMethodProcessor
,它是Spring内部用于处理@EventListener
注解的方法的类。但通常情况下,你不需要直接与这些内部类打交道。
二、使用步骤
在Spring Boot中,自定义事件的发布与监听主要依赖于Spring Framework的事件发布-订阅机制。以下是创建、发布和监听自定义事件的基本步骤:
1. 定义自定义事件
首先,你需要定义一个继承自ApplicationEvent
的自定义事件类。这个类可以包含任何你希望在事件触发时传递的数据。
import org.springframework.context.ApplicationEvent;
public class CustomEvent extends ApplicationEvent {
private String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
2. 发布自定义事件
要发布事件,你需要获取ApplicationEventPublisher
的实例,然后调用它的publishEvent
方法。这通常在Spring管理的Bean中完成。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Component
public class EventPublisher {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void doStuffAndPublishAnEvent(final String message) {
System.out.println("Publishing custom event. ");
CustomEvent customEvent = new CustomEvent(this, message);
applicationEventPublisher.publishEvent(customEvent);
}
}
3. 监听自定义事件
要监听事件,你需要创建一个实现ApplicationListener
接口的类,并指定要监听的事件类型。你也可以使用@EventListener
注解来简化监听器的创建。
使用ApplicationListener
接口:
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("Received custom event - " + event.getMessage());
}
}
或者使用@EventListener
注解:
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class CustomEventListener {
@EventListener
public void handleCustomEvent(CustomEvent event) {
System.out.println("Received custom event - " + event.getMessage());
}
}
4. 触发事件发布
最后,你需要在某个地方触发事件发布。这通常是通过调用上面创建的EventPublisher
类的doStuffAndPublishAnEvent
方法来完成的。
@Autowired
private EventPublisher eventPublisher;
public void sendEvent() {
eventPublisher.doStuffAndPublishAnEvent("Hello, world!");
}
这就是在Spring Boot 3中创建、发布和监听自定义事件的基本流程。注意,虽然Spring Boot 3可能在某些细节上与之前的版本有所不同,但事件处理的核心机制自Spring Framework的早期版本以来一直相对稳定。确保你正在查看与你正在使用的Spring Boot版本相对应的文档和示例。
三、使用代码示例
示例1:不定义事件,直接发布Object对象,同步
1)定义发送事件对象
public class UserEntity {
private long id;
private String name;
private String msg;
}
2)定义事件监听器
可以添加条件condition,限制监听具体的事件
@Slf4j
@Component
public class RegisterListener {
@EventListener(condition = "#entity.id != null and #entity.async==false ")
public void handlerEvent(UserEntity entity) {
try {
// 休眠5秒
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("handlerEvent: {}", entity);
}
}
3)定义发送接口以及实现类
public interface IRegisterService {
public void register(String name);
}
@Service
public class RegisterServiceImpl implements IRegisterService {
@Resource
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void register(String name) {
UserEntity entity = new UserEntity();
entity.setName(name);
entity.setId(1L);
entity.setMsg("新用户注册同步调用");
applicationEventPublisher.publishEvent(entity);
}
}
4)测试Controller类,进行测试
@Slf4j
@Controller
public class TestController {
@Resource
private IRegisterService registerService;
@RequestMapping("test")
@ResponseBody
public void test1(String name) {
registerService.register(name);
log.info("执行同步调用结束");
}
}
在浏览器中输入地址:http://localhost/test?name=nik
控制台输出:
handlerEvent: UserEntity(id=1, name=nik, msg=新用户注册同步调用)
执行同步调用结束
示例2:异步发布
1)在启动类添加异步注解 @EnableAsync
2)在监听方法上添加注解 @Async
@Async
@EventListener(condition = "#entity.name != null and #entity.async ")
public void handlerEventAsync(UserEntity entity) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("handlerEventAsync: {}", entity);
}
3)在service中添加异步发送方法
@Override
public void registerAsyn(String name) {
UserEntity entity = new UserEntity();
entity.setName(name);
entity.setId(1L);
entity.setMsg("新用户注册异步调用");
entity.setAsync(true);
applicationEventPublisher.publishEvent(entity);
}
4)测试
@RequestMapping("test")
@ResponseBody
public void test(String name) {
registerService.registerAsyn(name);
log.info("执行异步调用结束");
}
控制台输出:
执行异步调用结束
handlerEventAsync: UserEntity(id=1, name=nik, msg=新用户注册异步调用)
示例3:在事务提交后发布事件
比如,用户注册成功后给用户发送成功短信,那么注册成功必然是注册方法事务提交成功后才代表成功。
Spring提供了注解@TransactionalEventListener
监听事务事件,在@EventListener
基础上增加了属性phase,包含以下四个值:
AFTER_COMMIT
,事务提交成功后,默认BEFORE_COMMIT
,事务提交前AFTER_ROLLBACK
,事务回滚后AFTER_COMPLETION
,事务完成,AFTER_COMMIT
或AFTER_ROLLBACK
1)自定义事务处理事件
public class RegisterCommitEvent extends ApplicationEvent {
@Getter
@Setter
private String msg;
@Getter
@Setter
private String name;
public RegisterCommitEvent(UserEntity source) {
super(source);
this.msg = source.getMsg();
this.name = source.getName();
}
}
2)在处理方法上添加事务注解,@Transactional
@Override
@Transactional
public void registerCommit(String name) {
UserEntity entity = new UserEntity();
entity.setName(name);
entity.setMsg("新用户注册事务提交事件");
RegisterCommitEvent registerEvent = new RegisterCommitEvent(entity);
userDao.save(entity);
// 发送事件
applicationEventPublisher.publishEvent(registerEvent);
}
3)添加事务事件监听
@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handlerEventCmmit(RegisterCommitEvent event) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("handlerEventCmmit: {}", event);
}
4)测试
@RequestMapping("test")
@ResponseBody
public void test(String name) {
registerService.registerCommit(name);
log.info("执行事务调用结束");
}
控制台输出:
执行事务调用结束
handlerEventCmmit: RegisterCommitEvent[source=UserEntity(id=0, name=nik, msg=新用户注册事务提交事件)]
总结
Spring ApplicationEvent事件处理机制使用起来简单方便,可以对程序进行有效解耦。
虽然可以发送任意类型的对象,但是在实际业务中容易产生混乱,建议根据实际业务,定义好各类事件,并在监听方法中实现异步处理。