Access to spring beans from OncePerRequestFilter

10,125

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());
}
Share:
10,125
aryanRaj_kary
Author by

aryanRaj_kary

Updated on August 20, 2022

Comments

  • aryanRaj_kary
    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
    aryanRaj_kary over 7 years
    Can you explain more on how it would help in this case.
  • kuhajeyan
    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
    aryanRaj_kary over 7 years
    even now, requests are going to filter before hitting the spring dispatcher servlet, and which is why the service is null I think.
  • kuhajeyan
    kuhajeyan over 7 years
    yes, filter is not instantiated by spring hence it can not autowired by spring. I have updated my answer
  • aryanRaj_kary
    aryanRaj_kary over 7 years
    How 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
    Satyendra Kumar over 7 years
    Even 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
    aryanRaj_kary over 7 years
    Yes, true. I have other filters before this authCheckFilter, not sure why but I am getting error,
  • aryanRaj_kary
    aryanRaj_kary over 7 years
    com.ibm.ws.webcontainer.webapp.WebApp logServletError SRVE0293E: [Servlet Error]-[SpringDispatcherServer]: java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?org.springframework.web.filter.DelegatingFilterPr‌​oxy.doFilter(Delegat‌​ingFilterProxy.java:‌​252)com.ibm.ws.webco‌​ntainer.filter.Filte‌​rInstanceWrapper.doF‌​ilter(FilterInstance‌​Wrapper.java:195)com‌​.ibm.ws.webcontainer‌​.filter.WebAppFilter‌​Chain.doFilter(WebAp‌​pFilterChain.java:91‌​)com.ibm.tsc.qa.util‌​.ValidationFilter.do‌​FilterInternal(Valid‌​ationFilter.java:32)
  • Satyendra Kumar
    Satyendra Kumar over 7 years
    Do you have ContextLoaderListener added to web.xml ?
  • aryanRaj_kary
    aryanRaj_kary over 7 years
    I 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
    YetAnotherBot over 5 years
    OncePerRequestFilter cannot override final init method. Also, overriding initFilterBean() and calling getFilterConfig() inside it return null. Not sure, how this worked for the upvoters.