8

I have the following piece of code in my initializer:

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Filter[] getServletFilters() {

        DelegatingFilterProxy shiroFilter = new DelegatingFilterProxy("shiroFilter");
        shiroFilter.setTargetFilterLifecycle(true);

        return new Filter[]{new CorsFilter(),shiroFilter};
    }
}

I want CorsFilter to be executed before ShiroFilter. However, the Spring documentation doesn't say that the order in which the filters are executed is determined by their order in the returned array.

If it is, can someone please clarify it? If not, can someone suggest how do I guarantee the execution order of filters?

Sled
  • 18,541
  • 27
  • 119
  • 168
pdeva
  • 43,605
  • 46
  • 133
  • 171

3 Answers3

14

Just to keep the question up to date.

Use the spring @Order - Annotation

@Component(value = "myCorsFilter")
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    [...]

}

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { AppConfiguration.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] { 
             new DelegatingFilterProxy("myEncodingFilter"), 
             new DelegatingFilterProxy("myCorsFilter"),    // or just new CorsFilter()
             new DelegatingFilterProxy("mySecurityFilter") //...
        };
    }

}
alex
  • 8,904
  • 6
  • 49
  • 75
6

Filters are registered in the order of the array.

This results in ServletContext.addFilter() being called in the order of items, however, I am not sure if this actually results in the filters being executed by the container in the order that they were registered.

Tomcat for example seems to use a HashMap to store filters so I wouldn't expect filters to necessarily run in the order that they were added.

Spring does provide a org.springframework.web.filter.CompositeFilter, so I would simply return a single CompositeFilter containing the two filters that you actually want to use.

Sled
  • 18,541
  • 27
  • 119
  • 168
Phil Webb
  • 8,119
  • 1
  • 37
  • 37
  • 1
    +1 I was just looking into how to do this with `CompositeFilter`. Create a `DelegatingFilterProxy` that holds a `CompositeFilter` to which you pass a `List` of the `Filter` beans you want to register. – Sotirios Delimanolis Dec 17 '13 at 23:20
  • can you provide the transformed code sample with CompositeFilter. That would make this answer much better for future readers. – pdeva Dec 17 '13 at 23:23
  • apparently `CompositeFilter` does not work with any filter that uses Apache Shiro's `OncePerRequestFilter`, since its `OncePerRequestFilter.doFilter()` method checks if the filter has already been executed by name, and the name in this case becomes 'compositeFilter' (instead of the executing filter), thus resulting in the `OncePerRequestFilter` never being executed. – pdeva Dec 17 '13 at 23:38
  • Apparently the `OncePerRequestFilter` class is present in both Shiro and Spring, and using `CompositeFilter` breaks them both. so definitely not a solution. – pdeva Dec 17 '13 at 23:50
  • 2
    Looks like there isn't a particularly easy way to do it. This answer suggests resorting back to XML due to the limitation in the Servlet API (http://stackoverflow.com/questions/6560969/how-to-define-servlet-filter-order-of-execution-using-annotations). You might also look at wrapping the CompositeFilter in a OncePerRequestFilter. Or perhaps just subclass ShiroFilter and call the CorsFilter directly. – Phil Webb Dec 18 '13 at 04:54
  • I've created a ticket in Tomcat based on this thread: https://issues.apache.org/bugzilla/show_bug.cgi?id=56764 – Rossen Stoyanchev Jul 23 '14 at 12:53
  • 2
    Tomcat's use of a `HashMap` is a red herring: the `Filter`s are registered and executed in the proper order when declared in XML, but the order of `Filter`s discovered and registered via annotations cannot be controlled. For that, you *must* use `web.xml` or some kind of composite `Filter`. – Christopher Schultz Jul 27 '14 at 02:18
0

For someone who may want to use javax annotation instead of spring Order, @javax.annotation.Priority annotation also could be used instead of @Order like answer from "dit" above .

dillip
  • 1,782
  • 17
  • 16