第四十八讲-事件监听器
第四十八讲-事件监听器
Spring当中有一个非常好的机制,就是事件。事件可以实现组件之间的解耦。本讲我们来看一下事件监听器的使用
1. 事件监听器实现1-实现ApplicationListener接口
如下面的代码:
// 事件解耦例子
@Configuration
public class A48_1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_1.class);
context.getBean(MyService.class).doBusiness();
context.close();
}
// 自定义一个事件,需要继承Spring提供的ApplicationEvent
static class MyEvent extends ApplicationEvent {
public MyEvent(Object source) { // source 事件源; 事件源是类名+方法名
super(source);
}
}
@Component
static class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
// 想要发布一个事件,就要准备一个事件发布器
@Autowired
private ApplicationEventPublisher publisher;
public void doBusiness() {
log.debug("主线业务");
// 主线业务完成后需要做一些支线业务,如发现短信和发送邮箱,下面是问题代码
// 事件源
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
}
@Component
// 发送短信事件监听器
// 自定义事件监听器(事件消费者)需要实现Spring提供的ApplicationListener接口
static class SmsApplicationListener implements ApplicationListener<MyEvent> {
private static final Logger log = LoggerFactory.getLogger(SmsApplicationListener.class);
@Override
public void onApplicationEvent(MyEvent event) {
log.debug("发送短信");
}
}
// 发送邮箱事件监听器 --> 该监听器只会关注自己感兴趣的事件(在泛型中定义)
@Component
static class EmailApplicationListener implements ApplicationListener<MyEvent> {
private static final Logger log = LoggerFactory.getLogger(EmailApplicationListener.class);
@Override // 事件发生时执行的方法
public void onApplicationEvent(MyEvent event) {
log.debug("发送邮件");
}
}
}
2. 通过@EventListener方法
接下来我们再通过@EventListener方法来监听事件,此外我们发现主线业务,发送邮件,发送短信这三件事是同一个线程串行执行的,因此呢,我们改为异步的形式来实现:
@Configuration
public class A48_2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_2.class);
context.getBean(MyService.class).doBusiness();
context.close();
}
static class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
@Component
static class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
@Autowired
private ApplicationEventPublisher publisher;
public void doBusiness() {
log.debug("主线业务");
// 主线业务完成后需要做一些支线业务,下面是问题代码
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
}
@Component
static class SmsService {
private static final Logger log = LoggerFactory.getLogger(SmsService.class);
@EventListener // 监听事件,对MyService发布的事件感兴趣
public void listener(MyEvent myEvent) {
log.debug("发送短信");
}
}
@Component
static class EmailService {
private static final Logger log = LoggerFactory.getLogger(EmailService.class);
@EventListener // 监听事件,对MyService发布的事件感兴趣
public void listener(MyEvent myEvent) {
log.debug("发送邮件");
}
}
@Bean
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
return executor;
}
@Bean
public SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor) {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setTaskExecutor(executor);
return multicaster;
}
}
3. @EventListener的原理
接下来我们来研究一下@EventListener注解解析的原理,这里呢我们自定义一个注解,用来取代Spring提供的@EventListener注解来演示一遍:
package com.cherry.springa47;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class A48_2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A48_2.class);
for (String beanName : context.getBeanDefinitionNames()) {
Object bean = context.getBean(beanName);
// 获取该类的所有方法
for (Method method : bean.getClass().getDeclaredMethods()) {
// 判断哪个类上加上了@SmsService注解
if (method.isAnnotationPresent(MyListener.class)) {
ApplicationListener listener = new ApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println(event);
// 获取方法的参数类型信息(监听器方法需要的事件类型)
Class<?> eventType = method.getParameterTypes()[0];
// 判断类型是否匹配 --> 筛选事件类型
if (eventType.isAssignableFrom(event.getClass())) {
try {
method.invoke(bean, event); //反射调用
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
// 让我们自己写的监听器加入到Spring容器中
context.addApplicationListener(listener);
}
}
}
context.getBean(MyService.class).doBusiness();
context.close();
}
static class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
@Component
static class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);
@Autowired
private ApplicationEventPublisher publisher;
public void doBusiness() {
log.debug("主线业务");
// 主线业务完成后需要做一些支线业务,下面是问题代码
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
}
@Component
static class SmsService {
private static final Logger log = LoggerFactory.getLogger(SmsService.class);
@MyListener // 监听事件,对MyService发布的事件感兴趣
public void listener(MyEvent myEvent) {
log.debug("发送短信");
}
}
@Component
static class EmailService {
private static final Logger log = LoggerFactory.getLogger(EmailService.class);
@MyListener // 监听事件,对MyService发布的事件感兴趣
public void listener(MyEvent myEvent) {
log.debug("发送邮件");
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyListener {
}
@Bean
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
return executor;
}
@Bean
public SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor) {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setTaskExecutor(executor);
return multicaster;
}
}
分类:
Spring 高级49讲
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构