41

I am trying to set the order of execution of 2 filters in my spring boot application which have same url mapping. I have tried using 2 filter registration beans in my main Application class as below but that did not work. I want the authorizationFilter to be hit first then the validationFilter. But it is always hitting ONLY validationFilter when both are configured. If I comment out the validationFilter, it hits authorizationFilter.

@Bean
public FilterRegistrationBean authorizationFilter(){
    FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
    filterRegBean.setFilter(authorizationFilter);
    List<String> urlPatterns = new ArrayList<String>();
    urlPatterns.add("/v1/*");
    filterRegBean.setUrlPatterns(urlPatterns);
    return filterRegBean;
}

@Bean
public FilterRegistrationBean validationFilter(){
    FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
    filterRegBean.setFilter(validationFilter);
    List<String> urlPatterns = new ArrayList<String>();
    urlPatterns.add("/v1/*");
    filterRegBean.setUrlPatterns(urlPatterns);
    return filterRegBean;
}

I have also tried introducing web.xml and converting the executable jar to war file.

<web-app>   
<filter>
    <filter-name>authorizationFilter</filter-name>
    <filter-class>com.security.filter.AuthorizationFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>authorizationFilter</filter-name>
    <url-pattern>/v1/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>validationFilter</filter-name>
    <filter-class>com.security.validation.ValidationFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>validationFilter</filter-name>
    <url-pattern>/v1/*</url-pattern>
</filter-mapping>
</web-app>

But the application doesn't seem to recognize the web.xml, as it hits only the validation filter with the configuration above. I appreciate any inputs in resolving this. Thanks

Tuna
  • 2,937
  • 4
  • 37
  • 61
Manu
  • 456
  • 1
  • 4
  • 6
  • You would have to go to great lengths to get a Spring Boot app to use a `web.xml` (but it is possible, per the "traditional" sample in Spring Boot). – Dave Syer Mar 17 '14 at 12:09
  • [How to Define a Spring Boot Filter? | Baeldung](https://www.baeldung.com/spring-boot-add-filter) might be helpful. – Jason Law Mar 19 '20 at 15:13

3 Answers3

51

setOrder(int) method does the job.

below is an example

@Configuration
@EnableAutoConfiguration
@EnableWebMvc
@ComponentScan
public class Application {

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        SecurityFilter securityFilter = new SecurityFilter();
        registrationBean.setFilter(securityFilter);
        registrationBean.setOrder(2);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean contextFilterRegistrationBean() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        RequestContextFilter contextFilter = new RequestContextFilter();
        registrationBean.setFilter(contextFilter);
        registrationBean.setOrder(1);
        return registrationBean;
    }
}
Aritz
  • 30,971
  • 16
  • 136
  • 217
  • 2
    @AmitGupta You Can add Order annotation in the definition of the filter class. like: @ Component @ Order(1) public class ApiCrossDomainFilter extends GenericFilterBean {} – Junv Jan 22 '17 at 02:20
  • What worked for me is `registrationBean.setOrder(Integer.MAX_VALUE);`, `registrationBean.setOrder(Integer.MAX_VALUE-1);` – Amit Kumar Gupta Jan 22 '17 at 07:44
  • 2
    @AmitKumarGupta Order can be any number between Integer.MIN_VALUE and Integer.MAX_VALUE as defined in Ordered interface. Integer.MAX_VALUE basically means that it will have THE LOWEST PRIORITY and MAX_VALUE -1 has one higher priority than previous one. HIGHER value has LOWER precedence. It is basically same but if example didn't work then maybe there is some other filter that is being executed earlier and the process doesn't come to the your filter. – wonhee Jun 11 '19 at 00:22
20

Spring Boot sorts your FilterRegistrationBean using AnnotationAwareOrderComparator before applying them to the servlet context. The RegistrationBean is not currently Ordered so there is no way to set the order by calling a method, but you can work around that by creating subclasses and adding @Order to them. I think making the base class Ordered and providing a setter is probably a useful thing to do in the framework (open an issue on github if you agree).

Update: Ordered was added in 1.0.x.

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • Thanks Dave for your quick response. I will try the proposed workaround. It will be very useful if you can add this feature in spring boot. – Manu Mar 17 '14 at 12:36
  • I have created 2 sub classes for 'FilterRegistrationBean' and defined '@Order' with values 1 and 2 and using each of them to register my filters. But during start up of the application I am getting -Caused by: java.lang.IllegalArgumentException: Filter must not be null. at org.springframework.boot.context.embedded.FilterRegistrationBean.onStartup(FilterRegistrationBean.java:232) – Manu Mar 17 '14 at 14:04
  • I'm guessing that means the filter is null? Did you forget to set it? – Dave Syer Mar 17 '14 at 17:08
  • I have set the filters but still seeing the filter as 'nulll' on start up. ``@Bean public AuthFilterRegistrationBean authorizationFilter(){ AuthFilterRegistrationBean filterRegistrationBean = new AuthFilterRegistrationBean(); filterRegistrationBean.setFilter(authorizationFilter); //set url pattern return filterRegistrationBean; }`` ``@Component @Order(1) public class AuthFilterRegistrationBean extends FilterRegistrationBean{ //constructor @Override public void setFilter(Filter filter) { super.setFilter(filter); } }`` – Manu Mar 18 '14 at 18:46
  • 1
    We must be missing something. Anyway if you use a snapshot of boot the registration bean base class has setOrder() now. – Dave Syer Mar 18 '14 at 18:49
  • ``@Component`` on ``FilterRegistrationBean`` subclasses was the reason for filters being null. It was fine after deleting that. But spring boot main configuration class is not registering more than one bean of type ``FilterRegistrationBean``. I have tried with snapshot too, but it is the same behaviour. so my second filter is no being registered. – Manu Mar 19 '14 at 16:09
  • Do you actually have 2 bean definitions with unique names? It would help to see the code. – Dave Syer Mar 19 '14 at 18:25
  • divided the code into 2 comments //configuration class ``@Autowired AuthorizationFilter authorizationFilter; @Autowired ValidationFilter validationFilter; @Bean public AuthFilterRegistrationBean authorizationFilter(){ AuthFilterRegistrationBean authBean = new AuthFilterRegistrationBean (); authBean.setFilter(authorizationFilter); List urlPatterns = new ArrayList(); urlPatterns.add("/v1/*"); authBean.setUrlPatterns(urlPatterns); return authBean; }`` – Manu Mar 20 '14 at 10:00
  • ``@Bean public ValidationFilterRegistrationBean validationFilter(){ ValidationFilterRegistrationBean valBean = new ValidationFilterRegistrationBean(); valBean.setFilter(validationFilter); List urlPatterns = new ArrayList(); urlPatterns.add("/v1/*"); valBean.setUrlPatterns(urlPatterns); return valBean; } @Order(1) public class AuthFilterRegistrationBean extends FilterRegistrationBean{ //constructor //set Filter } @Order(2) public class ValidationFilterRegistrationBean extends FilterRegistrationBean{ //constructor //set Filter }`` – Manu Mar 20 '14 at 10:05
  • You `@Autowired` the filters into fields, which might be dangerous since the registration beans have to be instantiated super early. How about if you just switch to a snapshot and set the order on the registration bean in your original version? Can you not put the whole project on github? P.S. it would be better to add code to the question rather than in comments (since formatting is fubar). – Dave Syer Mar 20 '14 at 10:16
  • @DaveSyer With 2 filters ordered 1 and 2, which one executes first? – Abhijit Sarkar May 26 '16 at 01:25
  • 1 then 2. Isn't that obvious? – Dave Syer May 26 '16 at 06:26
  • Dave, what about `org.springframework.web.filter.GenericFilterBean`? It seems to have no notion of `Order`, doesn't implement `Ordered`, therefore is unorderable as a filter? – Adam Mar 15 '17 at 11:02
  • It's a base class though. You can add an annotation to your concrete class (or use ` FilterRegistrationBean` as suggested above). – Dave Syer Mar 15 '17 at 17:28
-9

Bean name will solve your problem: @Bean("aFilter").