Issue
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.
Solution
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.
Answered By - rhinds
Answer Checked By - Pedro (JavaFixing Volunteer)