Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.5k views
in Technique[技术] by (71.8m points)

spring - Configuring RequestContextListener in SpringBoot

I have a Spring-Boot application which uses Spring-Security. I have a request scoped bean that I want to autowire into one of my custom Filters in the security filter chain, but at the moment it is not working.

I understand that some config is needed to use request scoped beans outside of the DispatcherServlet, and have read this http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/beans.html#beans-factory-scopes-other But have not had any success yet:

For Servlet 3.0+, this can done programmatically via the WebApplicationInitializer interface.

(I am using latest Tomcat so is servlet 3+)

I have tried using both the RequestContextListener and the RequestContextFilter (docs say that they, and the DispatcherServlet, do the exact same thing), but in both cases I still get errors because my autowired object is null:

My attempt to register the Filter

@Configuration
@ComponentScan
@EnableAutoConfiguration
class Application extends SpringBootServletInitializer  {

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

    @Override public void onStartup( ServletContext servletContext ) throws ServletException {
        super.onStartup( servletContext )
        servletContext.addFilter("requestContextFilter", new RequestContextFilter() ).addMappingForUrlPatterns(null, false, "/*")
    }

My attempt to register the Listener

@Configuration
@ComponentScan
@EnableAutoConfiguration
class Application extends SpringBootServletInitializer  {

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

    @Override public void onStartup( ServletContext servletContext ) throws ServletException {
        super.onStartup( servletContext )
        servletContext.addListener( new RequestContextListener() ) 
    }

Am I missing something obvious? I have had a look at the auto config source code for Spring Boot and haven't come across anything yet.


UPDATE

I was being an idiot, I had added my Filter in my SpringSecurity configuration, inside the configure() method:

http.addFilterBefore( new PreAuthFilter(), BasicAuthenticationFilter )

but hadn't registered the new Filter as a Bean. As per M. Denium's comment below, I didn't need all that additional config explicitly adding the listener/filter, just registering the bean was enough.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As detailed in the update/comments, this was caused by my own stupidity.

Spring-Boot is able to autowire Request/Session scoped beans into filter's that are outside of the DispatcherServlet As per Spring's documentation, we need to add the RequestContextListener or RequestContextFilter to enable this functionality:

To support the scoping of beans at the request, session, and global session levels (web-scoped beans), some minor initial configuration is required before you define your beans. (This initial setup is not required for the standard scopes, singleton and prototype.) ...

If you access scoped beans within Spring Web MVC, in effect, within a request that is processed by the Spring DispatcherServlet, or DispatcherPortlet, then no special setup is necessary: DispatcherServlet and DispatcherPortlet already expose all relevant state.

To handle this, I needed to register a RequestContextListener bean:

@Bean public RequestContextListener requestContextListener(){
    return new RequestContextListener();
} 

If you don't register that bean, you will get an error stating that you are trying to access the Request scope outside of DispatcherServlet.

The problem I experienced(autowired objects just not being injected) was caused by the fact that I was just registering my custom filter as a standard class instance, not a Spring managed bean:

http.addFilterBefore( new PreAuthFilter(), BasicAuthenticationFilter )

To solve this, I just moved the creation of the PreAuthFilter to a sepearte @Bean method, the @Autowired functionality then worked fine.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...