• 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,不难理解吧。

  • 相关阅读:
    软件测试 接口测试 Postman测试工具 接口测试的流程 执行接口测试 接口关联 环境变量和全局变量 内置动态参数以及自动有的动态参数
    BGP→→
    小米手环8pro重新和手机配对解决办法
    GO语言-管道channel
    你的第一款开源视频分析框架
    02 uniapp/微信小程序 项目day02
    网络安全(黑客)自学
    C++二分查找算法:数组中占绝大多数的元素
    第52节:cesium 3DTiles模型特效+选中高亮(含源码+视频)
    tar.gz文件修复
  • 原文地址:https://blog.csdn.net/hnzmdpan/article/details/133831904