Spring ComponentScan导致java.lang.IllegalStateException:ApplicationEventMulticaster未初始化

时间:2015-07-10 08:07:00

标签: java spring spring-mvc spring-security

我有一个半工作(如在runnable中)Spring Boot网络应用程序,我正在尝试添加安全性。我有OAuth2的REST服务,但我也需要在WebMvc端进行身份验证。我无法按照我的方式工作,所以我重构了配置:

public class SpringConfigurationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
    @Override
    protected Class<?>[] getRootConfigClasses()
    {
        return new Class[] { AppConfiguration.class };
    }

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

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

}

@Configuration
@ComponentScan(basePackages = {"co.sens.rest", "co.sens.data", "co.sens.docdata", "co.sens.aggregators"})
@Import({ WebMvcConfig.class, OAuth2ServerConfig.class, SecurityConfiguration.class, CustomUserDetailsService.class })
public class AppConfiguration {
}

因此,目的是扫描应用程序本身(co.sens.rest)中的组件以及引用的jar中的外部代码。保持数据访问分离的主要目的。

由于这样做,我现在收到以下错误,我可以收集到的是因为Spring Security很快就开始了。它正在尝试将我的UserRepository自动装配到我的自定义UserDetailsS​​ervice。

在添加AbstractAnnotationConfigDispatcherServletInitializer之前,我可以让它运行但我无法在网络上获得安全性

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'embeddedServletContainerCustomizerBeanPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.rest.config.SecurityConfiguration co.sens.rest.config.MethodSecurityConfig.securityConfig; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'securityConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.setContentNegotationStrategy(org.springframework.web.accept.ContentNegotiationStrategy); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration.setConfigurers(java.util.List); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.rest.controllers.UsersController co.sens.rest.controllers.web.WebController.usersController; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'usersController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.data.Operations co.sens.rest.controllers.UsersController.dataOperations; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'operations': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.docdata.DocStoreOperations co.sens.data.Operations.docStoreOperations; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'docStoreOperations': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private co.sens.docdata.repositories.UserRepository co.sens.docdata.DocStoreOperations.userRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@553a3d88: startup date [Fri Jul 10 08:55:21 BST 2015]; root of context hierarchy
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:232)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:615)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:465)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at co.sens.rest.Application.main(Application.java:11)

完整的堆栈跟踪:http://pastebin.com/SJLa2pSc

更新

配置:

package co.sens.rest.config;

@Configuration
@ComponentScan(basePackages = {"co.sens.data", "co.sens.docdata", "co.sens.aggregators"})
public class AppConfiguration {
}

public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

}

@Configuration
public class OAuth2ServerConfig {

    private static final String SENS_RESOURCE_ID = "sens";

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            resources.resourceId(SENS_RESOURCE_ID).stateless(false); //.authenticationEntryPoint(new RestAuthenticationEntryPoint()); //.stateless(false);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {

            http
                    .authorizeRequests()
                    .antMatchers("/api").access("#oauth2.hasScope('read') and hasRole('ROLE_USER')");

        }
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

        @Autowired
        private TokenStore tokenStore;

        @Autowired
        private UserApprovalHandler userApprovalHandler;

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Autowired
        private CustomUserDetailsService userDetailsService;

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory().withClient("sensapp")
                    .resourceIds(SENS_RESOURCE_ID)
                    .authorizedGrantTypes("authorization_code", "refresh_token",
                            "password")
                    .authorities("USER")
                    .scopes("read", "write")
                    .secret("secret");
        }

        @Bean
        public TokenStore tokenStore() {
            return new InMemoryTokenStore();
        }

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints
                    .tokenStore(tokenStore)
                    .userApprovalHandler(userApprovalHandler)
                    .authenticationManager(authenticationManager)
                    .userDetailsService(userDetailsService);
        }

        @Bean
        @Primary
        public DefaultTokenServices tokenServices() {
            DefaultTokenServices tokenServices = new DefaultTokenServices();
            tokenServices.setSupportRefreshToken(true);
            tokenServices.setTokenStore(this.tokenStore);
            return tokenServices;
        }
        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer.realm("sens/client");
        }
    }

    protected static class Approvals {

        @Autowired
        private ClientDetailsService clientDetailsService;

        @Autowired
        private TokenStore tokenStore;

        @Bean
        public ApprovalStore approvalStore() throws Exception {
            TokenApprovalStore store = new TokenApprovalStore();
            store.setTokenStore(tokenStore);
            return store;
        }

        @Bean
        @Lazy
        @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
        public SensUserApprovalHandler userApprovalHandler() throws Exception {
            SensUserApprovalHandler handler = new SensUserApprovalHandler();
            handler.setApprovalStore(approvalStore());
            handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
            handler.setClientDetailsService(clientDetailsService);
            handler.setUseApprovalStore(true);
            return handler;
        }
    }
}

public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/web/**").authenticated()
                .antMatchers("/login/**", "/resources/**").permitAll()
                .and()
                .formLogin().loginProcessingUrl("/login").failureUrl("/login?authorization_error=true").defaultSuccessUrl("/web/home").loginPage("/login").permitAll()
                .and()
                .logout().logoutUrl("/logout").logoutSuccessUrl("/login")
                .permitAll();
    }

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
                auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
public class ServletInitializer extends AbstractDispatcherServletInitializer {

    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.scan(ClassUtils.getPackageName(getClass()));
        return context;
    }

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

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        DelegatingFilterProxy filter = new DelegatingFilterProxy("springSecurityFilterChain");
        filter.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher");
        servletContext.addFilter("springSecurityFilterChain", filter).addMappingForUrlPatterns(null, false, "/*");
    }

}
@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {

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

    //@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry
                .addResourceHandler("/resources/**")
                .addResourceLocations("/resources/")
                .setCachePeriod(31556926);
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
    }

    @Bean
    public TemplateResolver defaultTemplateResolver() {
        TemplateResolver result = new ServletContextTemplateResolver();
        result.setPrefix("/WEB-INF/templates/");
        result.setSuffix(".html");
        result.setTemplateMode("LEGACYHTML5");
        result.setCacheable(false); // TODO Only for dev
        return result;
    }

    @Bean
    public SpringTemplateEngine templateEngine(TemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        Set<IDialect> dialects = new HashSet<>();
        dialects.add(new SpringSecurityDialect());
        templateEngine.setAdditionalDialects(dialects);
        return templateEngine;
    }

    @Bean
    public ThymeleafViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }

    @Bean
    public ContentNegotiatingViewResolver contentViewResolver() throws Exception {
        ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
        contentNegotiationManager.addMediaType("json", MediaType.APPLICATION_JSON);

        MappingJackson2JsonView defaultView = new MappingJackson2JsonView();
        defaultView.setExtractValueFromSingleKeyModel(true);

        ContentNegotiatingViewResolver contentViewResolver = new ContentNegotiatingViewResolver();
        contentViewResolver.setContentNegotiationManager(contentNegotiationManager.getObject());
        contentViewResolver.setDefaultViews(Arrays.<View>asList(defaultView));
        return contentViewResolver;
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

安全调试日志

2015-07-14 14:05:31.352  INFO 12373 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2015-07-14 14:05:31.352  INFO 12373 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2015-07-14 14:05:31.387  INFO 12373 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 35 ms
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/token']
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/web/home'; against '/oauth/token'
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/token_key']
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/web/home'; against '/oauth/token_key'
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/check_token']
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/web/home'; against '/oauth/check_token'
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : No matches found
2015-07-14 14:05:31.460 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration$NotOAuthRequestMatcher@7d97df04
2015-07-14 14:05:31.461 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : matched
2015-07-14 14:05:31.462 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-07-14 14:05:31.462 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-07-14 14:05:31.463 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-07-14 14:05:31.463 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@63d700f9
2015-07-14 14:05:31.463 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2015-07-14 14:05:31.463 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/web/home'; against '/logout'
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 5 of 11 in additional filter chain; firing Filter: 'OAuth2AuthenticationProcessingFilter'
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.o.p.a.BearerTokenExtractor         : Token not found in headers. Trying request parameters.
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.o.p.a.BearerTokenExtractor         : Token not found in request parameters.  Not an OAuth2 request.
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] p.a.OAuth2AuthenticationProcessingFilter : No token in request, will continue chain.
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2015-07-14 14:05:31.464 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2015-07-14 14:05:31.465 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2015-07-14 14:05:31.466 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.session.SessionManagementFilter  : Requested session ID 09564785AF0DDD41AB2645CEEE04E79E is invalid.
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/web/home'; against '/api'
2015-07-14 14:05:31.467 DEBUG 12373 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Public object - authentication not attempted
2015-07-14 14:05:31.468 DEBUG 12373 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /web/home reached end of additional filter chain; proceeding with original chain
2015-07-14 14:05:31.622 ERROR 12373 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine             : [THYMELEAF][http-nio-8080-exec-1] Exception processing template "index": Error retrieving value for property "username" of authentication object of class org.springframework.security.authentication.AnonymousAuthenticationToken (index)
2015-07-14 14:05:31.624 DEBUG 12373 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2015-07-14 14:05:31.626 ERROR 12373 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Error retrieving value for property "username" of authentication object of class org.springframework.security.authentication.AnonymousAuthenticationToken (index)] with root cause

1 个答案:

答案 0 :(得分:1)

如果您使用的是Spring Boot,则应移除SpringConfigurationInitializer并使用SpringBootServletInitializer。例如:

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

有关详细信息,请参阅Spring Boot参考。