• spring session 导致 HttpSessionListener 失效


    1. @ServletComponentScan(basePackages = "com")
    2. @EnableRedisHttpSession
    3. public class StartAuthApplication {
    4. public static void main(String[] args) {
    5. SpringApplication.run(StartAuthApplication.class, args);
    6. }
    7. }
    8. @WebListener
    9. public static class MyHttpSessionListener implements HttpSessionListener {
    10. public MyHttpSessionListener() {
    11. System.out.println("MyHttpSessionListener");
    12. }
    13. @Override
    14. public void sessionCreated(HttpSessionEvent se) {
    15. log.info("sessionCreated new session {}", se.getSession().getId());
    16. }
    17. @Override
    18. public void sessionDestroyed(HttpSessionEvent se) {
    19. log.info("sessionDestroyed session destroyed {}", se.getSession().getId());
    20. }
    21. }

    上面的代码,看上去没有什么问题吧。本意思是想通过ServletComponentScan+WebListener来添加一个监听器。但是 使用到了spring session (redis),会导致上面的代码, MyHttpSessionListener 里的代码不起作用,即 本文的主题 HttpSessionListener 失效

    其实原因也很简单,就是因为 HttpSerssionListener实现类,原本应该由servlet容调(比如TOMCAT)来调用,现在因为spring session的存在(可以理解为spring从中倒腾了下),调用顺序变成了 tomcat --> spring --> HttpSessionListener。 直接上代码

    1. public class SessionEventHttpSessionListenerAdapter
    2. implements ApplicationListener, ServletContextAware {
    3. public void onApplicationEvent(AbstractSessionEvent event) {
    4. if (this.listeners.isEmpty()) {
    5. return;
    6. }
    7. HttpSessionEvent httpSessionEvent = createHttpSessionEvent(event);
    8. // 重点在这里 this.listeners。 这是spring代码里的一个对象
    9. for (HttpSessionListener listener : this.listeners) {
    10. if (event instanceof SessionDestroyedEvent) {
    11. listener.sessionDestroyed(httpSessionEvent);
    12. }
    13. else if (event instanceof SessionCreatedEvent) {
    14. listener.sessionCreated(httpSessionEvent);
    15. }
    16. }
    17. }
    18. }

    spring 抽象了一层 AbstractSessionEvent, this.listeners, 又是熟悉的套路,从这里可以看出,我们写的HttpSessionListener,变成了二等公民,由spring 的SessionEventHttpSessionListenerAdapter 这个 一等公民来决定什么时候调用。

    所以,问题的根本原因,我们写的MyHttpSessionListener,之所以没有被调用,是因为spring的变量 this.listeners 没有得到我们写的实现类。继续想一下,spring 为什么没有拿到呢??

    解决办法,把这个实现类,变成一个bean吧。

    1. @WebListener
    2. // 添加一个注解就可以了
    3. @Component
    4. public static class MyHttpSessionListener implements HttpSessionListener {
    5. }

    通过上面的分析能得出一个结论:由于spring的存在,原本本该由servlet直接调用我们的代码,有可能会变成由servlet 调用spring, 再由 spring 来调用我们的代码。而spring在调用我们的代码时候,它是怎们我们的代码的呢(比如某个接口的实现类有哪些),很有可能会以BEAN的形式进行查找某对象,从而调用对象的方法,原因也很好理解,毕意spring的另一个功能就是IOC,不难理解吧。

  • 相关阅读:
    字节跳动 DanceCC 工具链系列之Xcode LLDB耗时监控统计方案
    【Vivado那些事儿】使用 Python 提取 ILA 数据
    Linux基础命令(示例代码 + 解释)
    Activity的isFinishing()判断Activity的状态
    Android APK瘦身实践:二次瘦身如何再减少大小?(4M—2.9M)
    Knockoutjs属性绑定(Bindings)之流程控制(Control flow)
    牛客网 ACM 模式 输入输出
    信息学奥赛一本通——1899:【17NOIP提高组】小凯的疑惑
    CSS 文本属性篇
    动手学习深度学习 05:深度学习计算
  • 原文地址:https://blog.csdn.net/hnzmdpan/article/details/133831904