4

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
  • 503
  • 2
  • 7
  • 28
  • Add the code for `AuthCheckFilter`. – manish Oct 20 '16 at 03:31
  • See this http://stackoverflow.com/questions/7882042/how-can-i-get-a-spring-bean-in-a-servlet-filter – Satyendra Kumar Oct 20 '16 at 04:29
  • 1
    Not sure whether the above link would help, because the control won't even go to "Spring Dispatcher Servlet", so even If we register the Filter as bean in spring config xml, it won't help us I think. – aryanRaj_kary Oct 20 '16 at 09:04
  • I don't know if I am lucky or the issue has been fixed, but with spring version 4.3.3. The autowired Just worked for me without any issue. – best wishes Jan 10 '19 at 13:16

3 Answers3

4

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

ekem chitsiga
  • 5,523
  • 2
  • 17
  • 18
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.

Satyendra Kumar
  • 357
  • 2
  • 13
  • 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. – aryanRaj_kary Oct 24 '16 at 03:32
  • 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 `` – Satyendra Kumar Oct 24 '16 at 03:51
  • Yes, true. I have other filters before this authCheckFilter, not sure why but I am getting error, – aryanRaj_kary Oct 24 '16 at 03:57
  • com.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) – aryanRaj_kary Oct 24 '16 at 03:57
  • Do you have ContextLoaderListener added to web.xml ? – Satyendra Kumar Oct 24 '16 at 04:02
  • 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] – aryanRaj_kary Oct 24 '16 at 06:11
1

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());
}
kuhajeyan
  • 10,727
  • 10
  • 46
  • 71
  • Can you explain more on how it would help in this case. – aryanRaj_kary Oct 20 '16 at 09:07
  • /* 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 http://stackoverflow.com/questions/4140448/difference-between-and-in-servlet-mapping-url-pattern – kuhajeyan Oct 20 '16 at 09:11
  • even now, requests are going to filter before hitting the spring dispatcher servlet, and which is why the service is null I think. – aryanRaj_kary Oct 20 '16 at 09:34
  • yes, filter is not instantiated by spring hence it can not autowired by spring. I have updated my answer – kuhajeyan Oct 20 '16 at 09:42
  • 9
    `OncePerRequestFilter` cannot override `final` `init` method. Also, overriding `initFilterBean()` and calling `getFilterConfig()` inside it return null. Not sure, how this worked for the upvoters. – YetAnotherBot Dec 04 '18 at 07:02