盘点 SpringBoot Listener

首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜

文章合集 : 🎁 juejin.cn/post/694164…

Github : 👉 github.com/black-ant

CASE 备份 : 👉 gitee.com/antblack/ca…

一 .前言

本篇文档来完善 Spring 体系中 Listener 的相关概念 :

主要内容 :

  • Listener 的处理流程
  • Listener 的同步和异步处理
  • 常见的 Listener 处理

Spring-listener.jpg

二 . Listener 的基础使用

基础使用中包括四个步骤 :

  • 构建一个 TranTO 用于承载数据
  • 构建一个 Event 用于发布
  • 构建一个 Listener 接受事件及处理
  • 主业务中发布事件

2.1 数据承载体

数据承载体用于在发布事件的同事携带数据给 Listener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
java复制代码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 构建了一个对象

1
2
3
4
5
6
7
8
java复制代码  public class DefaultEvent extends ApplicationEvent {

private Logger logger = LoggerFactory.getLogger(this.getClass());

public DefaultEvent(ListenerTranTO tranTO) {
super(tranTO);
}
}

2.3 构建一个 Listener 接受事件及处理

1
2
3
4
5
6
7
8
9
10
java复制代码@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 主业务中发布事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
java复制代码 @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…

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
java复制代码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

类型一 : 容器自动触发 , 触发流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
java复制代码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 的主要发布者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
java复制代码
// 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
java复制代码// 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 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
java复制代码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 代理

此处进行实际的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
java复制代码
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 的时机

1
2
3
4
5
6
7
java复制代码
//存在四个地方往 Set 中添加 Listener 对象

C- AbstractApplicationEventMulticaster # addApplicationListener(ApplicationListener<?> listener)
?- 手动添加 Listener , 具体哪些地方会调用就不详细说了
C- AbstractApplicationEventMulticaster # retrieveApplicationListeners
?- 这里是从 defaultRetriever 添加到传入的 ListenerRetriever 中

四. SpringListener 异步处理

在不开启异步的情况下 , Listener 是非异步的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
java复制代码@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 中配置监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码/

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

1
2
3
4
5
6
java复制代码public static void main(String[] args) {

SpringApplication springApplication = new SpringApplication(Sb2Application.class);
springApplication.addListeners(new SecondListener());
springApplication.run(args);
}

方式三 : application.propeties 文件中配置

1
2
java复制代码
context.listener.classes=....listener.class

方式四 : 相关模块中添加 listener

在部分场景中 , 可以往 Web 容器中通过 AddListener 的方式添加

  • JPA 的 @EntityListeners

方式五 : 注解添加

1
2
3
4
java复制代码@EventListener
public void event(Object event){
System.out.println("MyEventHandle 接收到事件:" + event.getClass());
}

方式五 : WebListener

1
2
3
4
5
6
java复制代码@WebListener
public class DefaultHttpSessionListener implements HttpSessionListener {
//...........
}

// PS : Application 方法上需要标注注解 @ServletComponentScan

# WebListener 使用 (与此相同的还有 ServletContextListener )

这里说一下 WebListener 的使用方式 , HttpSessionListener 也是 EventListener 的子接口之一 , 通过实现该 Listener 可以实现对 Session 的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
java复制代码@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 : 补充流程图

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%