首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164…
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca…
一 .前言
本篇文档来完善 Spring 体系中 Listener 的相关概念 :
主要内容 :
- Listener 的处理流程
- Listener 的同步和异步处理
- 常见的 Listener 处理
二 . Listener 的基础使用
基础使用中包括四个步骤 :
- 构建一个 TranTO 用于承载数据
- 构建一个 Event 用于发布
- 构建一个 Listener 接受事件及处理
- 主业务中发布事件
2.1 数据承载体
数据承载体用于在发布事件的同事携带数据给 Listener
public class ListenerTranTO {
private String eventName;
private Map<String, String> eventInfo;
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
public Map<String, String> getEventInfo() {
return eventInfo;
}
public void setEventInfo(Map<String, String> eventInfo) {
this.eventInfo = eventInfo;
}
@Override
public String toString() {
return "ListenerTranTO{" +
"eventName='" + eventName + '\'' +
", eventInfo=" + eventInfo +
'}';
}
}
2.2 构建发布 Event
可以看到 , Event 是基于 ApplicationEvent 构建了一个对象
public class DefaultEvent extends ApplicationEvent {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public DefaultEvent(ListenerTranTO tranTO) {
super(tranTO);
}
}
2.3 构建一个 Listener 接受事件及处理
@Component
public class DefaultListener implements ApplicationListener<DefaultEvent> {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void onApplicationEvent(DefaultEvent event) {
logger.info("------> DefaultEvent Listner , Properties [{}] <-------", String.valueOf(event.getSource()));
}
}
2.4 主业务中发布事件
@Autowired
private ApplicationContext context;
@Override
public void run(ApplicationArguments args) throws Exception {
logger.info("------> Default Event Publish Start >>>>> <-------");
ListenerTranTO tranTO = new ListenerTranTO();
Map<String, String> infoMap = new HashMap<>();
infoMap.put("info", "This is in Info");
infoMap.put("message", "Listener Success");
tranTO.setEventInfo(infoMap);
tranTO.setEventName("DefaultListener");
context.publishEvent(new DefaultEvent(tranTO));
logger.info("------> Default Event Publish End >>>>> [{}] <-------", tranTO.toString());
}
}
三 . Listener 流程解析
这部分主要是说明 Listener 在 整个体系中的运用 , 先来看一下常见的几个 Listener , 首先看一下官方对 ApplicationListener 的定义 : 由应用程序事件侦听器实现的接口 , 基于观察者设计模式的标准java.util.EventListener接口。
这里回顾一下 观察者模式 的相关概念 :
观察者模式意图 : 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
参考 @ blog.csdn.net/zzg19950824…
public interface Observer {
public void update();
}
//两个实现类:
public class Observer1 implements Observer {
@Override
public void update() {
System.out.println("observer1 has received!");
}
}
public class Observer2 implements Observer {
@Override
public void update() {
System.out.println("observer2 has received!");
}
}
//Subject接口及实现类:
public interface Subject {
/*增加观察者*/
public void add(Observer observer);
/*删除观察者*/
public void del(Observer observer);
/*通知所有的观察者*/
public void notifyObservers();
/*自身的操作*/
public void operation();
}
public abstract class AbstractSubject implements Subject {
private Vector<Observer> vector = new Vector<Observer>();
@Override
public void add(Observer observer) {
vector.add(observer);
}
@Override
public void del(Observer observer) {
vector.remove(observer);
}
@Override
public void notifyObservers() {
Enumeration<Observer> enumo = vector.elements();
while(enumo.hasMoreElements()){
enumo.nextElement().update();
}
}
}
public class MySubject extends AbstractSubject {
@Override
public void operation() {
System.out.println("update self!");
notifyObservers();
}
}
//测试类:
public class ObserverTest {
public static void main(String[] args) {
Subject sub = new MySubject();
sub.add(new Observer1());
sub.add(new Observer2());
sub.operation();
}
}
//输出:
update self!
observer1 has received!
observer2 has received!
3.1 Listener 的触发方式
Listerner的触发主要有以下几种 :
- 容器启动时自动触发
- 手动发布 publishEvent
类型一 : 容器自动触发 , 触发流程
C- AbstractApplicationContext # refresh()
其中大部分是在这个流程中完成触发 , 通常都是通过 publish 进行发布
this.applicationContext.publishEvent(new ServletWebServerInitializedEvent(this.webServer, this.applicationContext));
C50- AbstractApplicationContext
M50_10- publishEvent(ApplicationEvent event)
M50_11- publishEvent(Object event, @Nullable ResolvableType eventType)
// Step 1 : 发布 Event 事件
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
} else {
// 此处如果不是 ApplicationEvent , 则构建 PayloadApplicationEvent -> PS:M50_11_01
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
// 此处获取事件内 Object 类型
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// 如果可能,立即进行多播,或者在多播器初始化后延迟多播 -> PS:M50_11_02
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// 也可以通过父上下文发布事件
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}else {
this.parent.publishEvent(event);
}
}
}
// PS:M50_11_01 PayloadApplicationEvent 是什么 ?
C- PayloadApplicationEvent
?- 携带任意有效负载的ApplicationEvent
I- ResolvableTypeProvider
F- private final T payload;
M- getResolvableType() : 返回描述此实例的ResolvableType
- return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getPayload()));
PS:M50_11_02 Listener 的 多播是什么?
Listener 的 多播是什么 ?
将所有事件多播给所有注册的侦听器,让侦听器忽略它们不感兴趣的事件. 监听器通常会对传入的事件对象执行相应的instanceof检查。
同时 , 可以异步处理 , 指定一个替代任务执行器,使侦听器在不同的线程中执行,例如在线程池中执行
总结 : 可以把其当成Listener 的主要发布者
// Step 1 : 事件多播的发布方式
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Step 2 : 对象的创建地方
C- AbstractApplicationContext
F- Set<ApplicationEvent> earlyApplicationEvents : 在多播器设置之前发布的ApplicationEvents
// 事件的多播器创建的地方是在 AbstractApplicationContext :
C- AbstractApplicationContext
M- refush
- initApplicationEventMulticaster()
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果 APPLICATION_EVENT_MULTICASTER_BEAN_NAME (applicationEventMulticaster) 中存在 , 则直接从Bean 工厂获取
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
} else {
// 构建一个新 SimpleApplicationEventMulticaster , 并且注册
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
// Step 3 : 来看一下 earlyApplicationEvents 的使用
C- AbstractApplicationContext
protected void registerListeners() {
// 首先注册静态指定的侦听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 获得所有的 ApplicationListener , 此处会根据 type 获取所有的 ApplicationListener
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 往 ApplicationEventMulticaster 中添加 Listener
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 发布早期应用事件
// 此处首先获取原本的 earlyEventsToProcess 对象 , 用于缓存 ,同时清空之前的镀锡
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
// 可以看到 , 最后仍然会调用 multicastEvent 进行消息的发布
3.2 Listener 的循环处理
此处调用 multicastEvent 进行最后的操作 , 主要有几个步骤 :
- resolveDefaultEventType 获得 事件的类型
- getTaskExecutor 获得 Executor -> PS:M50_12_1
- 获得所有的 Listenr
// Step 2 : 循环所有的 Listener
C50- AbstractApplicationContext
M50_12- multicastEvent(ApplicationEvent event)
- getApplicationListeners 获取所有的 Listeners -> M50_12_01
/**
* 循环 Listener
**/
C- SimpleApplicationEventMulticaster
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// 获取 Listener 对象
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}else {
invokeListener(listener, event);
}
}
}
// PS : ApplicationEventMulticaster 接口 , 主要实现类是 SimpleApplicationEventMulticaster
C- ApplicationEventMulticaster
M- void addApplicationListener(ApplicationListener<?> listener) : 添加一个侦听器,用于通知所有事
M- void addApplicationListenerBean(String listenerBeanName) : 添加一个侦听器bean,用于通知所有事件
M- void removeApplicationListener(ApplicationListener<?> listener) : 从通知列表中删除侦听器
M- void removeApplicationListenerBean(String listenerBeanName) : 从通知列表中删除侦听器bean
M- void removeAllListeners() : 删除所有注册到这个多播广播的监听器
M- void multicastEvent(ApplicationEvent event) : 将给定的应用程序事件组播到适当的侦听器
M- void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) : 将给定的应用程序事件组播到适当的侦听器
// PS : 补充 SimpleApplicationEventMulticaster 详见下文
以下通过 eventType 获得 ApplicationListener 类
C- AbstractApplicationEventMulticaster
// M50_12_01 getApplicationListeners 主流程
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// 快速检查ConcurrentHashMap上的现有条目...
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
if (this.beanClassLoader == null ||(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// listener检索器的完全同步构建和缓存
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
// 获取 ApplicationListener 集合
Collection<ApplicationListener<?>> listeners =retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
} else {
// 没有监听检索缓存 则 没有必要同步
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
C- AbstractApplicationContext
// 实际检索给定事件和源类型的应用程序监听器
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
// 通常为 ListenerRetriever , 这是一个Helper类,它封装一组特定的目标侦听器,允许高效检索预筛选的侦听器
// 每个事件类型和源类型都会缓存此Helper类的实例
synchronized (this.retrievalMutex) {
// 获得 Listener 对象
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// 添加以编程方式注册的侦听器,包括来自ApplicationListenerDetector的侦听器(单例bean和内部bean)ans).
for (ApplicationListener<?> listener : listeners) {
// 判断是否支持该 Event
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
// 按bean名添加侦听器,可能与上面以编程方式注册的侦听器重叠
if (!listenerBeans.isEmpty()) {
// 因为此处时Bean 名称 , 所以需要通过BeanFactory 构建
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
// 校验是否支持当前 Event
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
retriever.applicationListeners.add(listener);
}
else {
retriever.applicationListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
else {
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
retriever.applicationListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}
// 对 allListeners 进行排序
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}
return allListeners;
}
// 获取 Listener
C- AbstractApplicationEventMulticaster
// Helper类,它封装一组特定的目标Listener,允许高效检索预筛选的Listener
PVC- ListenerRetriever
F- Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>()
F- Set<String> applicationListenerBeans = new LinkedHashSet<>()
PS:M50_12_1 : getTaskExecutor 获取 Executor
返回此多播器的当前任务执行器
3.3 Invoke 代理
此处进行实际的调用
C- SimpleApplicationEventMulticaster
M- invokeListener(ApplicationListener<?> listener, ApplicationEvent event)
- 获取 ErrorHandler
- doInvokeListener 代理 Listener
- 如果出现异常 , errorHandler.handleError(err)
M- doInvokeListener(ApplicationListener listener, ApplicationEvent event)
- listener.onApplicationEvent(event) 发起Event 处理
// Step 3 : invoke Listener 类
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}catch (Throwable err) {
errorHandler.handleError(err);
}
}else {
doInvokeListener(listener, event);
}
}
// Event 处理
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
listener.onApplicationEvent(event);
}
补充 存放 Listener 的时机
//存在四个地方往 Set 中添加 Listener 对象
C- AbstractApplicationEventMulticaster # addApplicationListener(ApplicationListener<?> listener)
?- 手动添加 Listener , 具体哪些地方会调用就不详细说了
C- AbstractApplicationEventMulticaster # retrieveApplicationListeners
?- 这里是从 defaultRetriever 添加到传入的 ListenerRetriever 中
四. SpringListener 异步处理
在不开启异步的情况下 , Listener 是非异步的
@Configuration
@EnableAsync
public class AsyncListenerConfiguration implements AsyncConfigurer {
/**
* Spring Async 配置信息
*
* @return
*/
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
// 设置线程池的数目
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(20);
threadPoolTaskExecutor.setQueueCapacity(50);
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
/**
* 异步监听
**/
@Component
public class AsyncListener {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 此处使用 Async 异步处理
*
* @param defaultEvent
*/
@Async
@EventListener
public void doAsyncEvent(DefaultEvent defaultEvent) {
logger.info("------> 通过异步监听 :[{}] , Thread is :[{}]<-------", defaultEvent.getSource(), Thread.currentThread().getId());
}
}
// 发布事件
context.publishEvent(new DefaultEvent(tranTO));
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
2021-05-31 15:02:53.284 INFO 23640 --- [ main] c.g.s.s.demo.listener.DefaultListener : ------> DefaultEvent Listner , Properties [ListenerTranTO{eventName='DefaultListener', eventInfo={message=Listener Success, info=This is in Info}}] <-------
2021-05-31 15:02:53.287 INFO 23640 --- [ main] c.g.s.s.demo.listener.DefaultListener : ------> Listener Thread 情况 :[1] <-------
2021-05-31 15:02:53.297 INFO 23640 --- [lTaskExecutor-1] c.g.s.s.demo.listener.AsyncListener : ------> 通过异步监听 :[ListenerTranTO{eventName='DefaultListener', eventInfo={message=Listener Success, info=This is in Info}}] , Thread is :[330]<-------
2021-05-31 15:03:03.288 INFO 23640 --- [ main] c.g.s.source.demo.listener.TestListener : ------> Default Event Publish End >>>>> [ListenerTranTO{eventName='DefaultListener', eventInfo={message=Listener Success, info=This is in Info}}] -- [1] <-------
// 可以看到 , 此处发布后 , 同步监听停了10秒 ,而异步监听成功处理
// 原理 :
AsyncExecutionInterceptor : 主要是方法进行了异步代理
总结
这文章完善了 Spring 体系中的 Listener 模块 , 总体可以分为2种情况 :
同步情况 : AbstractApplicationContext 中循环所有的 Listener 进行处理
异步情况 : 首先对方法进行代理 ,在调用时 ,通过 Async 配置的线程池中开启一个新线程进行处理
附录
# Listener 的注册方式
转载自 @ www.cnblogs.com/linlf03/p/1…
方式一 : spring.factories 中配置监听器
/
public class FirstListener implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("hello, first listener");
}
}
// 在spring.factories文件中增加配置监听器
// 原理可以看看这一篇文章 : https://juejin.cn/post/6955489109225930789
org.springframework.context.ApplicationListener=com.example.demo.listener.FirstListener
方式二 : Main 函数中添加 Listener
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Sb2Application.class);
springApplication.addListeners(new SecondListener());
springApplication.run(args);
}
方式三 : application.propeties 文件中配置
context.listener.classes=....listener.class
方式四 : 相关模块中添加 listener
在部分场景中 , 可以往 Web 容器中通过 AddListener 的方式添加
- JPA 的 @EntityListeners
方式五 : 注解添加
@EventListener
public void event(Object event){
System.out.println("MyEventHandle 接收到事件:" + event.getClass());
}
方式五 : WebListener
@WebListener
public class DefaultHttpSessionListener implements HttpSessionListener {
//...........
}
// PS : Application 方法上需要标注注解 @ServletComponentScan
# WebListener 使用 (与此相同的还有 ServletContextListener )
这里说一下 WebListener 的使用方式 , HttpSessionListener 也是 EventListener 的子接口之一 , 通过实现该 Listener 可以实现对 Session 的操作
@WebListener
public class DefaultHttpSessionListener implements HttpSessionListener {
private static final Logger LOG = LoggerFactory.getLogger(DefaultHttpSessionListener.class);
private final AtomicInteger counter = new AtomicInteger();
@Override
public void sessionCreated(HttpSessionEvent se) {
LOG.info("New session is created. Adding Session to the counter.");
counter.incrementAndGet(); //incrementing the counter
updateSessionCounter(se);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
LOG.info("Session destroyed. Removing the Session from the counter.");
counter.decrementAndGet(); //decrementing counter
updateSessionCounter(se);
}
private void updateSessionCounter(HttpSessionEvent httpSessionEvent) {
//Let's set in the context
httpSessionEvent.getSession().getServletContext()
.setAttribute("activeSession", counter.get());
LOG.info("Total active session are {} ", counter.get());
}
}
// PS : Application 方法上需要标注注解 @ServletComponentScan
该方案的实现实现流程 :
public void tellNew() {
// Notify interested session event listeners
fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
// Notify interested application event listeners
Context context = manager.getContext();
Object listeners[] = context.getApplicationLifecycleListeners();
if (listeners != null && listeners.length > 0) {
HttpSessionEvent event =
new HttpSessionEvent(getSession());
for (int i = 0; i < listeners.length; i++) {
if (!(listeners[i] instanceof HttpSessionListener))
continue;
HttpSessionListener listener =
(HttpSessionListener) listeners[i];
try {
context.fireContainerEvent("beforeSessionCreated",
listener);
listener.sessionCreated(event);
context.fireContainerEvent("afterSessionCreated", listener);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
try {
context.fireContainerEvent("afterSessionCreated",
listener);
} catch (Exception e) {
// Ignore
}
manager.getContext().getLogger().error
(sm.getString("standardSession.sessionEvent"), t);
}
}
}
}
// Context 的处理逻辑
ServletListenerRegistrationBean 中进行注册
更新日志 :
- V20210804 : 补充流程图