Access to spring beans from OncePerRequestFilter
Solution 1
You filter is being configured outside the Spring container. Hence your @Autowired dependency is not injected.
To have your Filter bean managed by Spring without also tightly coupling it to Spring infrastructure through the use of SpringBeanAutowiringSupport suggested , you can use the DelegatingFilterProxy abstraction
Define AuthCheckFilter filter as a bean in your application context e.g
@Bean
public Filter authCheckFilter(){
AuthCheckFilter filter = new AuthCheckFilter();
//supply dependencies
return filter;
}
Then in your web.xml specify your filter with filter-class as org.springframework.web.filter.DelegatingFilterProxy and the filter name must match the authCheckFilter bean name in the context
At runtime DelegatingFilterProxy filter will delegate to a fully configured bean with the name authCheckFilter in the context (which must be a Filter)
<filter>
<filter-name>authFilterCheck</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>authCheckFilter</filter-name>
<url-pattern>/test/api/*</url-pattern>
</filter-mapping>
With this setup you wont have to worry about the lifecyles of your filter , root context or servlet
Solution 2
I don't know why @Autowire is not working, but I got it working by using setter injection.
For details:
Include this in your applicationContext.xml file
<bean name="AuthCheckFilter" class="x.y.AuthCheckFilter">
<property name="authCheckService" ref="authCheckService"/>
</bean>
<bean name="authCheckService" class="x.y.AuthCheckService"/>
Remember to provide a setter in AuthCheckFilter class for AuthCheckService.
Include this in your web.xml:
<filter>
<filter-name>AuthCheckFilter</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthCheckFilter</filter-name>
<url-pattern>/test/api/*</url-pattern>
</filter-mapping>
That's it. Now if you hit the url, you will get the non-null authCheckService.
Solution 3
add this in your init() OncePerRequestFilter, so spring can wire your autowired beans
public void init(FilterConfig filterConfig) throws ServletException {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
filterConfig.getServletContext());
}
aryanRaj_kary
Updated on August 20, 2022Comments
-
aryanRaj_kary over 1 year
I want to access a spring component from OncePerRequestFilter class, but I am getting null pointer when I access service, and I think the reason for that is the configuration. I think the filter is getting called before the spring dispatcher servlet due to the configuration. Any good way to get this done, suggestions please.
<servlet> <servlet-name>SpringDispatcherServer</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/config/springConfig.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringDispatcherServer</servlet-name> <url-pattern>/test/api/*</url-pattern> </servlet-mapping> <filter> <filter-name>AuthCheck</filter-name> <filter-class>org.test.util.AuthCheckFilter</filter-class> </filter> <filter-mapping> <filter-name>AuthCheck</filter-name> <url-pattern>/test/api/*</url-pattern> </filter-mapping>` public class AuthCheckFilter extends OncePerRequestFilter { @Autowired private AuthCheckService authCheckService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { log.info("authCheckService"+authCheckService);
and the logger prints null for "authCheckService"
-
aryanRaj_kary over 7 yearsCan you explain more on how it would help in this case.
-
kuhajeyan over 7 years/* is invasive url pattern it will override all other mapping, add /* to filter so the requests gone to filter before dispatch servlet. / means this will be default mapping, in case no any mapping found it will be served from here. So which should be your dispath servlet mapping read more stackoverflow.com/questions/4140448/…
-
aryanRaj_kary over 7 yearseven now, requests are going to filter before hitting the spring dispatcher servlet, and which is why the service is null I think.
-
kuhajeyan over 7 yearsyes, filter is not instantiated by spring hence it can not autowired by spring. I have updated my answer
-
aryanRaj_kary over 7 yearsHow about the other beans that are injected in the authCheckService bean, all those should be declared in spring context xml I think. And I have mybatis configuration also which is getting loaded using spring. So this now have to manually load instead of spring I guess.
-
Satyendra Kumar over 7 yearsEven if you declare beans in configuration file, it's not manual loading; you are just declaring which bean needs what (telling dependencies, spring will resolve it). Also you don't have to declare all beans in XML, because you can simply mix XML and annotations. So use XML configuration just for these beans, other beans can still be loaded using annotations and
<component-scan />
-
aryanRaj_kary over 7 yearsYes, true. I have other filters before this authCheckFilter, not sure why but I am getting error,
-
aryanRaj_kary over 7 yearscom.ibm.ws.webcontainer.webapp.WebApp logServletError SRVE0293E: [Servlet Error]-[SpringDispatcherServer]: java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:252)com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:195)com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:91)com.ibm.tsc.qa.util.ValidationFilter.doFilterInternal(ValidationFilter.java:32)
-
Satyendra Kumar over 7 yearsDo you have ContextLoaderListener added to web.xml ?
-
aryanRaj_kary over 7 yearsI do not have it, I removed it as I facing some file not found issue, even though I had a context param contextConfigLocation with the correct location. java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]
-
YetAnotherBot over 5 years
OncePerRequestFilter
cannot overridefinal
init
method. Also, overridinginitFilterBean()
and callinggetFilterConfig()
inside it return null. Not sure, how this worked for the upvoters.