Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

doFilter called twice, intended behaviour?

I'm working through the Java EE servlet tutorial and tried the mood example. I noticed the doFilter is getting called twice, once the servlet call is in the chain and the second time it isnt.

I added some printlns in the TimeOfDayFilter.java and in the MoodServlet.java to show this.

TimeOfDayFilter.java:

    ...
    System.out.println("TimeOfDay before"); //added
    chain.doFilter(req, res);
    System.out.println("TimeOfDay after"); //added
    ...

MoodServlet.java:

    ...
    response.setContentType("text/html;charset=UTF-8");

    System.out.println("MoodServlet"); //added

    PrintWriter out = response.getWriter();
    ...

The result from the glassfish server (3.1) window when calling the servlet is the following:

    INFO: mood was successfully deployed in 406 milliseconds.
    INFO: TimeOfDay before
    INFO: MoodServlet
    INFO: TimeOfDay after
    INFO: TimeOfDay before
    INFO: TimeOfDay after

Is this intended behaviour? If so, what is the reason for the extra call?

like image 926
user1348661 Avatar asked May 20 '13 09:05

user1348661


Video Answer


4 Answers

I solved the same issue after removing @Component in CustomFilter class.

like image 93
Mohan Pinapatruni Avatar answered Oct 25 '22 19:10

Mohan Pinapatruni


As Mohan has stated, @Component will make your filter be called twice if you have it already registered in you Application class, like this:

resources.add(new MyFilter());

If that's the case you have to choose between annotating it or registering it. But this is only valid for JAX-RS applications that use Spring. Not the topic of this question.

like image 40
Jonatas Avatar answered Oct 25 '22 21:10

Jonatas


chain.doFilter(request,response);

This will pass the control to the servlet the filter is associated with. But after the corresponding servlet is executed, the control comes back at the end of the above line and all the lines thereafter in the current doFilter() is executed.

If you want to pass the control permanently to the servlet and not letting it return to the filter, just add a

return;

at the end of chain.doFilter(request,response) line in the current filter.

like image 25
Rajarshee Mitra Avatar answered Oct 25 '22 21:10

Rajarshee Mitra


The Filter.doFilter method is called once per request. You can execute some code before other filters in the chain are called and also afterwards (in the order specified in the filter chain, as per the web.xml filter-mapping order), something like the following example:

public MyFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response,
           FilterChain chain) 
           throws IOException, ServletException
    {
        codeToExecuteBeforeOtherFiltersInTheChain(request, response);

        chain.doFilter(request, response);

        codeToExecuteAfterOtherFiltersInTheChain(request, response);

    }
}

If your filter is configured to dispatch REQUEST and FORWARD requests, then the MyFilter.doFilter method will be called once for the original request and once if the request has been forwarded:

Configure filter mapping using web.xml file:

...
<filter-mapping>
      <filter-name>MyFilter</filter-name>
      <url-pattern>/*</url-pattern>
      <dispatcher>REQUEST</dispatcher>
      <dispatcher>FORWARD</dispatcher>
</filter-mapping>
...

Configure filter mapping using @WebFilter annotation:

@WebFilter(urlPatterns = "/*", dispatcherTypes = {
    DispatcherType.REQUEST, DispatcherType.FORWARD
}) public MyFilter implements Filter {
    ...
}

To be able to check if the request has been forwarded, you can use the request attribute described here: How to know when the request is forwarded in a RequestWrapper object

For details about filters see: https://docs.oracle.com/cd/B32110_01/web.1013/b28959/filters.htm

like image 34
sebasbad Avatar answered Oct 25 '22 21:10

sebasbad