为什么使用基于java的配置的Spring应用程序无法正常工作

我最近开始使用Spring框架开发一个带有ojective的项目来开发它,没有XML配置文件,只有Java代码。

在当前时刻,我将以下文件添加到我的项目中:

WebAppConfig.java

@EnableWebMvc @ComponentScan(value="org.webapp") @Configuration public class WebAppConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926); registry.addResourceHandler("/css/**").addResourceLocations("/fonts/").setCachePeriod(31556926); registry.addResourceHandler("/img/**").addResourceLocations("/image/").setCachePeriod(31556926); registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926); } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } @Bean public InternalResourceViewResolver getInternalResourceViewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/jsp/"); resolver.setSuffix(".jsp"); return resolver; } } 

SecurityConfig.java

 @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("kleber").password("123").roles("USER"); } } 

SecurityWebApplicationInitializer.java

 @Order(value=2) public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { public SecurityWebApplicationInitializer() { super(SecurityConfig.class); } } 

在这种状态下,当我运行应用程序(在Eclipse中)时,浏览器显示Spring Security的默认登录表单,并在提交此表单后显示错误404。 如果我尝试直接输入url localhost:8080 / spring / index,我可以访问应该出现登录表单的页面。

如果我添加这个类:

WebAppInitializer.java

 @Order(value=1) public class WebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) { // Create the 'root' Spring application context AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); rootContext.register(WebAppConfig.class); // Manage the lifecycle of the root application context container.addListener(new ContextLoaderListener(rootContext)); // Create the dispatcher servlet's Spring application context AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext(); dispatcherContext.register(DispatcherConfig.class); // Register and map the dispatcher servlet ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } } 

取代web.xml,按照官方文档中的说明,在此链接中:

http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html

我甚至无法访问登录页面。 如果我向SecurityConfig类添加方法,也会发生同样的事情:

 protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/css/**", "/fonts/**", "/image/**", "/js/**").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("spring/index").permitAll() .failureUrl("spring/erro_login").permitAll() .defaultSuccessUrl("spring/home") .and() .logout() .logoutSuccessUrl("spring/logout") .permitAll(); } 

有人可以看到我错过了什么?

PS:

我的控制器是这样的:

 @Controller @RequestMapping(value="spring") public class SpringController { @RequestMapping(value="index") public ModelAndView index() { ModelAndView mav = new ModelAndView(); mav.setViewName("index"); return mav; } @RequestMapping(value="home") public ModelAndView home() { ModelAndView mav = new ModelAndView(); mav.setViewName("home"); return mav; } @RequestMapping(value="erro_login") public ModelAndView erro_login() { ModelAndView mav = new ModelAndView(); mav.setViewName("erro_login"); return mav; } @RequestMapping(value="erro_nao_autorizado") public ModelAndView erro_nao_autorizado() { ModelAndView mav = new ModelAndView(); mav.setViewName("erro_nao_autorizado"); return mav; } @RequestMapping(value="logout") public ModelAndView logout() { ModelAndView mav = new ModelAndView(); mav.setViewName("index"); return mav; } } 

UPDATE

此错误显示在Eclipse的控制台中

 Mar 29, 2014 1:28:02 PM org.apache.catalina.core.StandardContext listenerStart Grave: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener 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:265) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) 

在给出本主题的答案之后,我尝试从SecurityWebApplicationInitializer或WebAppInitializer中删除两个冲突的ContextListener注册之一。 在这两种情况下,我都会收到此错误:

 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.servlet.Filter org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain() throws java.lang.Exception] threw exception; nested exception is java.lang.IllegalArgumentException: 'spring/index?error' is not a valid redirect URL at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:581) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1025) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:921) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.servlet.Filter org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain() throws java.lang.Exception] threw exception; nested exception is java.lang.IllegalArgumentException: 'spring/index?error' is not a valid redirect URL at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:181) at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:570) ... 23 more Caused by: java.lang.IllegalArgumentException: 'spring/index?error' is not a valid redirect URL at org.springframework.util.Assert.isTrue(Assert.java:65) at org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler.setDefaultFailureUrl(SimpleUrlAuthenticationFailureHandler.java:98) at org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler.(SimpleUrlAuthenticationFailureHandler.java:43) at org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer.failureUrl(AbstractAuthenticationFilterConfigurer.java:199) at org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer.updateAuthenticationDefaults(AbstractAuthenticationFilterConfigurer.java:345) at org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer.loginPage(AbstractAuthenticationFilterConfigurer.java:285) at org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer.loginPage(FormLoginConfigurer.java:181) at org.webapp.security.SecurityConfig.configure(SecurityConfig.java:27) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:192) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:276) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:61) at org.webapp.security.SecurityConfig$$EnhancerByCGLIB$$f93abbff.init() at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:369) at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:322) at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:39) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:92) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerByCGLIB$$93d7a5f4.CGLIB$springSecurityFilterChain$0() at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerByCGLIB$$93d7a5f4$$FastClassByCGLIB$$eb934d27.invoke() at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:286) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerByCGLIB$$93d7a5f4.springSecurityFilterChain() at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160) ... 24 more Mar 29, 2014 4:18:30 PM org.apache.catalina.core.StandardContext listenerStart Grave: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.servlet.Filter org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain() throws java.lang.Exception] threw exception; nested exception is java.lang.IllegalArgumentException: 'spring/index?error' is not a valid redirect URL at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:581) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1025) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:921) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.servlet.Filter org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain() throws java.lang.Exception] threw exception; nested exception is java.lang.IllegalArgumentException: 'spring/index?error' is not a valid redirect URL at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:181) at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:570) ... 23 more Caused by: java.lang.IllegalArgumentException: 'spring/index?error' is not a valid redirect URL at org.springframework.util.Assert.isTrue(Assert.java:65) at org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler.setDefaultFailureUrl(SimpleUrlAuthenticationFailureHandler.java:98) at org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler.(SimpleUrlAuthenticationFailureHandler.java:43) at org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer.failureUrl(AbstractAuthenticationFilterConfigurer.java:199) at org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer.updateAuthenticationDefaults(AbstractAuthenticationFilterConfigurer.java:345) at org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer.loginPage(AbstractAuthenticationFilterConfigurer.java:285) at org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer.loginPage(FormLoginConfigurer.java:181) at org.webapp.security.SecurityConfig.configure(SecurityConfig.java:27) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:192) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:276) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:61) at org.webapp.security.SecurityConfig$$EnhancerByCGLIB$$f93abbff.init() at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:369) at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:322) at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:39) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:92) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerByCGLIB$$93d7a5f4.CGLIB$springSecurityFilterChain$0() at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerByCGLIB$$93d7a5f4$$FastClassByCGLIB$$eb934d27.invoke() at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:286) at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerByCGLIB$$93d7a5f4.springSecurityFilterChain() at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160) ... 24 more 

 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! 

WebAppInitializer ,您正在注册ContextLoaderListener

因为您正在使用AbstractSecurityWebApplicationInitializer和接受Class[]super 构造函数

创建一个新实例,该实例将使用指定的类实例化ContextLoaderListener。

它还注册了一个ContextLoaderListener 。 注意类javadoc

当与AbstractSecurityWebApplicationInitializer(Class...) ,它还将注册ContextLoaderListener 。 与AbstractSecurityWebApplicationInitializer()使用时,除了AbstractContextLoaderInitializer的子类之外,通常还会使用此类。

正如错误所述,您不能拥有两个ContextLoaderListener实例,因为它们都会尝试创建ApplicationContext并将其添加到ServletContext

我认为问题在于:

 .loginPage("spring/index").permitAll() 

应该是这样的:

 .loginPage("/spring/index").permitAll() //note the '/' at the beginning of the uri 

也许你的web.xml和基于java的configuration class之间存在一些冲突的重叠。 当我遇到与你相同的错误时,这就是根本原因。 我的解决方案是在web.xml注释掉重复的配置。

我上过课

MyContextLoaderListener扩展了ContextLoaderListener

在我的代码中的某个地方。 它未被使用。 Spring boot显然使用reflection来找到它。 我删除了文件,问题就消失了