Spring Rest(MVC + 安全性)Java 配置:"Cannot initialize context because there is already a root application context present"
SpringRest (MVC + Security) Java Configuration : "Cannot initialize context because there is already a root application context present"
我是 Spring 的新手,我已经遇到了一个关于基本配置的非常奇怪的问题。
Caused by: java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:297)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:173)
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:194)
... 7 more
我需要两种不同的 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() { ... }
时遇到了同样的错误
我应该 remove/add 来自 web.xml 的东西吗?
我正在使用 Wildfly 8,我已经不得不为 Wildfly 中的错误找到解决方法:如果 spring 库(罐子)未添加到 WEB-Inf/lib文件夹...
好的,我找到了解决方案。我现在没有覆盖两次 AbstractAnnotationConfigDispatcherServletInitializer,而是使用一个 class 实现 WebApplicationInitializer,并且我在这个 class.
中构建了我的两个 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,但这是另一个话题:)
我是 Spring 的新手,我已经遇到了一个关于基本配置的非常奇怪的问题。
Caused by: java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml! at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:297) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107) at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:173) at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:194) ... 7 more
我需要两种不同的 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() { ... }
时遇到了同样的错误我应该 remove/add 来自 web.xml 的东西吗? 我正在使用 Wildfly 8,我已经不得不为 Wildfly 中的错误找到解决方法:如果 spring 库(罐子)未添加到 WEB-Inf/lib文件夹...
好的,我找到了解决方案。我现在没有覆盖两次 AbstractAnnotationConfigDispatcherServletInitializer,而是使用一个 class 实现 WebApplicationInitializer,并且我在这个 class.
中构建了我的两个 servletpublic 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,但这是另一个话题:)