You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何同时使用SessionManager与AbstractAnnotationConfigDispatcherServletInitializer避免多ContextLoader*定义?

问题描述

现有以下两段代码:

public class SpringMVCWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 
    @Override 
    protected Class<?>[] getRootConfigClasses() { 
        return new Class[] { LoginApplicationConfig.class }; 
    } 
    @Override 
    protected Class<?>[] getServletConfigClasses() { 
        return null; 
    } 
    @Override 
    protected String[] getServletMappings() { 
        return new String[] { "/" }; 
    } 
} 

public class Initializer extends AbstractHttpSessionApplicationInitializer { 
    public Initializer() { 
        super(Config.class); 
    } 
}

请问如何在不产生多个ContextLoader*定义的前提下,同时使用SessionManager与AbstractAnnotationConfigDispatcherServletInitializer?


解决方案

核心问题在于AbstractAnnotationConfigDispatcherServletInitializer和AbstractHttpSessionApplicationInitializer都会触发Spring根上下文的初始化,分开使用会导致多个根上下文被创建,进而出现ContextLoader*重复定义的冲突。我们可以通过合并初始化逻辑来解决这个问题,这里提供两种常用且可靠的方式:

方式一:让MVC初始化器继承AbstractHttpSessionApplicationInitializer

直接修改你的SpringMVCWebAppInitializer,让它同时承担Session管理器的初始化职责,这样所有上下文初始化逻辑都在一个类中完成,从根源避免重复创建上下文:

public class SpringMVCWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    // 构造方法传入Session相关配置类,替代原有的Initializer类
    public SpringMVCWebAppInitializer() {
        super(Config.class);
    }

    @Override 
    protected Class<?>[] getRootConfigClasses() { 
        // 把LoginApplicationConfig和Session的Config合并到根上下文配置中
        return new Class[] { LoginApplicationConfig.class, Config.class }; 
    } 

    @Override 
    protected Class<?>[] getServletConfigClasses() { 
        return null; // 若需要Servlet级别(比如MVC专属)的配置,可在此指定,否则保持null
    } 

    @Override 
    protected String[] getServletMappings() { 
        return new String[] { "/" }; 
    } 
}

之后你可以删除原来独立的Initializer类,这样整个应用只会初始化一个根上下文,自然不会出现ContextLoader*重复定义的问题。

方式二:手动注册Session配置,避免自动上下文重复创建

如果不想修改现有初始化器的继承结构,可以在SpringMVCWebAppInitializer的onStartup方法中手动注册Session相关配置,绕过AbstractHttpSessionApplicationInitializer的自动上下文创建逻辑:

public class SpringMVCWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // 先执行父类的onStartup,完成MVC上下文的初始化
        super.onStartup(servletContext);
        
        // 手动初始化Session相关的根上下文,避免重复创建
        AnnotationConfigWebApplicationContext sessionContext = new AnnotationConfigWebApplicationContext();
        sessionContext.register(Config.class);
        
        // 检查是否已有ContextLoaderListener,防止重复注册
        if (servletContext.getAttribute(ContextLoader.CONTEXT_INITIALIZER_CLASSES) == null) {
            servletContext.addListener(new ContextLoaderListener(sessionContext));
        }
    }

    @Override 
    protected Class<?>[] getRootConfigClasses() { 
        return new Class[] { LoginApplicationConfig.class }; 
    } 

    @Override 
    protected Class<?>[] getServletConfigClasses() { 
        return null; 
    } 

    @Override 
    protected String[] getServletMappings() { 
        return new String[] { "/" }; 
    } 
}

不过这种方式需要额外做重复检查,逻辑相对繁琐,更推荐第一种方式——它更符合Spring的设计习惯,代码结构也更清晰。

最后要确认你的Config.class中已经正确配置了Session管理器,比如使用@EnableSpringHttpSession注解,或者指定了合适的Session存储实现,这样才能和MVC上下文无缝整合。

内容的提问来源于stack exchange,提问作者Jim Krikris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:52:46