SpringRest(MVC +安全性)Java配置:"无法初始化上下文,因为已存在根应用程序上下文"

时间:2016-08-11 15:17:56

标签: java spring spring-security spring-rest

我是Spring的新手,基本配置我已经遇到了一个非常奇怪的问题。

  

引起:java.lang.IllegalStateException:无法初始化上下文,因为已存在根应用程序上下文 - 检查web.xml中是否有多个ContextLoader *定义!       在org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:297)       在org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)       at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:173)       在io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:194)       ......还有7个

我需要两个不同的REST servlet:一个用于内部调用(查看服务器),另一个用于外部api。我还希望两个servlet共享一些服务,所以我使用SpringRootConfiguration来扫描包含两个拦截器和一个服务的包。

所有配置都是用Java完成的,只包含web.xml中的上下文和监听器

的web.xml

<context-param>
    <param-name>contextClass</param-name>
    <param-value>
        org.springframework.web.context.support.AnnotationConfigWebApplicationContext
    </param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

SpringRestExternalAppInitializer

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

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

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

@Override
protected String getServletName() {
    return "restexternal";
}

SpringRootConfiguration

@ComponentScan({"be.xperthis.common"})
@Configuration
public class SpringRootConfiguration {

}

SpringRestExternalConfiguration

@ComponentScan("com.polymedis.result.web.api")
@Configuration
public class SpringRestExternalConfiguration extends WebMvcConfigurationSupport {

@Autowired
private NoCacheHandler noCacheHandler;

@Autowired
private RestMetricHandler restMetrics;

@Override
public void addInterceptors(final InterceptorRegistry registry) {
    registry.addInterceptor(noCacheHandler);
    registry.addInterceptor(restMetrics);
}

@Override
public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}

@Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
    ....
}

@Override
public RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
    return new ApiVersionRequestMappingHandlerMapping(); //used to check a custom annotation on every RestController methods
}
}

理论上,应该有第二个Rest配置(内部),但是我在尝试理解异常的同时将其删除了......

注意:在Spring安全教程之后,我将SpringSecurityConfiguration放入getRootConfigClasses(){...}

时遇到了同样的错误

我应该从web.xml中删除/添加内容吗? 我使用Wildfly 8并且我已经必须找到Wildfly中的一个错误的解决方法:如果未在WEB-Inf / lib文件夹中添加spring库(jar),则不会拾取Spring配置... < / p>

1 个答案:

答案 0 :(得分:0)

好的,我找到了解决方案。我没有覆盖两次AbstractAnnotationConfigDispatcherServletInitializer,而是使用一个实现WebApplicationInitializer的类,我在这个类中构建了两个servlet。

public class SpringAppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(final ServletContext servletContext) throws ServletException {
    final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(SpringRootConfiguration.class, SpringSecurityConfig.class);
    servletContext.addListener(new ContextLoaderListener(rootContext));

    // Internal REST
    buildInternalRestContext(servletContext, rootContext);

    // External REST
    buildExternalRestContext(servletContext, rootContext);

    ...
}

public void buildExternalRestContext(final ServletContext servletContext, final AnnotationConfigWebApplicationContext rootContext) {
    final AnnotationConfigWebApplicationContext externalRestContext = new AnnotationConfigWebApplicationContext();
    externalRestContext.setParent(rootContext);
    externalRestContext.register(SpringRestExternalConfiguration.class);

    final ServletRegistration.Dynamic externalRestServlet = servletContext.addServlet("externalrest", new DispatcherServlet(externalRestContext));
    externalRestServlet.addMapping("/api/*");
}

public void buildInternalRestContext(final ServletContext servletContext, final AnnotationConfigWebApplicationContext rootContext) {
    final AnnotationConfigWebApplicationContext internalRestContext = new AnnotationConfigWebApplicationContext();
    internalRestContext.setParent(rootContext);
    internalRestContext.register(SpringRestConfiguration.class);

    final ServletRegistration.Dynamic restDispatcherServlet = servletContext.addServlet("rest", new DispatcherServlet(internalRestContext));
    restDispatcherServlet.addMapping("/rest/*");
}

}

我现在将继续设置SpringSecurity,但这是另一个主题:)