How to define Servlet filter order of execution in Spring Boot application
Asked Answered
D

3

42

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

Dimple answered 17/3, 2014 at 11:58 Comment(2)
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).Casting
How to Define a Spring Boot Filter? | Baeldung might be helpful.Counterspy
P
52

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;
    }
}
Parsonage answered 7/5, 2014 at 21:5 Comment(3)
@AmitGupta You Can add Order annotation in the definition of the filter class. like: @ Component @ Order(1) public class ApiCrossDomainFilter extends GenericFilterBean {}Kirshbaum
What worked for me is registrationBean.setOrder(Integer.MAX_VALUE);, registrationBean.setOrder(Integer.MAX_VALUE-1);Frazer
@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.Hemisphere
C
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.

Casting answered 17/3, 2014 at 12:7 Comment(14)
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.Dimple
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)Dimple
I'm guessing that means the filter is null? Did you forget to set it?Casting
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); } }Dimple
We must be missing something. Anyway if you use a snapshot of boot the registration bean base class has setOrder() now.Casting
@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.Dimple
Do you actually have 2 bean definitions with unique names? It would help to see the code.Casting
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<String> urlPatterns = new ArrayList<String>(); urlPatterns.add("/v1/*"); authBean.setUrlPatterns(urlPatterns); return authBean; }Dimple
@Bean public ValidationFilterRegistrationBean validationFilter(){ ValidationFilterRegistrationBean valBean = new ValidationFilterRegistrationBean(); valBean.setFilter(validationFilter); List<String> urlPatterns = new ArrayList<String>(); 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 }Dimple
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).Casting
@DaveSyer With 2 filters ordered 1 and 2, which one executes first?Boredom
1 then 2. Isn't that obvious?Casting
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?Enedina
It's a base class though. You can add an annotation to your concrete class (or use ` FilterRegistrationBean` as suggested above).Casting
E
-9

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

Exmoor answered 20/2, 2017 at 10:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.