Why Identical filterOrder Values Make Zuul Filters Unordered – A Deep Dive
This article explains Zuul’s filter lifecycle, how built‑in and custom filters are defined, the internal sorting algorithm based on filterOrder, why filters with the same order are considered unordered, and compares Zuul’s sorting with Spring’s @Order annotation, including code examples and diagrams.
Introduction
Recently a reader asked how Zuul orders two filters that have the same order value, which prompted an investigation of the source code.
What Is Zuul?
Zuul is the API‑gateway component of Spring Cloud, acting as an L7 gateway that provides dynamic routing, monitoring, resilience, security and other features. Most of its functionality is implemented through filters.
Zuul defines four filter lifecycles: pre , routing , post and error . Built‑in filters are enabled via the annotations @EnableZuulServer and @EnableZuulProxy.
The @EnableZuulProxy annotation also activates additional features, as shown in the following diagram.
How to Create a Custom Filter
To create a custom filter, extend the ZuulFilter class and implement the four abstract methods: filterType, filterOrder, shouldFilter and run. The following code demonstrates a simple pre‑filter that logs request information.
public class LogFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return RequestContext.getCurrentContext().sendZuulResponse();
}
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
log.info("zuul pre filter-->" + request.getRequestURL() + "-->" + request.getMethod());
return null;
}
}The four methods have the following purposes:
filterType : specifies the filter stage (pre, routing, post, error).
filterOrder : determines execution order; smaller values run earlier.
shouldFilter : a switch that decides whether the filter should run.
run : contains the actual filter logic.
Remember to annotate the Spring Boot main class with either @EnableZuulServer or @EnableZuulProxy so that Zuul’s functionality is activated.
How filterOrder Is Sorted
All filters are processed by the FilterProcessor.runFilters method, which obtains the filters via processZuulFilter. The core of the sorting logic is in FilterLoader.getInstance().getFiltersByType(sType):
Retrieve the filter list for a given filterType from a cache; if present, return it.
If not cached, create a new list and add all filters of that type.
Sort the list.
Store the sorted list back into the cache.
The sorting itself is performed by Collections.sort(list), which ultimately calls List.sort, then Arrays.sort, and finally the ComparableTimSort implementation that uses a binary‑search based algorithm.
Because ZuulFilter implements Comparable and overrides compareTo to compare the integer filterOrder, filters are ordered according to the numeric value of filterOrder.
What Happens When filterOrder Is Identical?
If two filters have the same filterOrder, the Integer.compare method returns 0, and Collections.sort does not swap their positions. Consequently, the relative order of those filters is undefined because the underlying collection returned by getAllFilters is a ConcurrentHashMap.values() set, which is unordered.
Important: If filterOrder is the same, Zuul filters are unordered.
Two Ways to Define Sorting Rules
You can control ordering in two ways:
Implement the Comparable interface in the class and override compareTo. This is the default used by Collections.sort(list).
Provide an external Comparator implementation and pass it to Collections.sort(list, comparator). For example, sorting integers in descending order:
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});Both approaches ultimately rely on the same binary‑search sorting algorithm.
Difference Between Comparable and Comparator
Comparableresides in java.lang and defines a natural ordering inside the class itself. Comparator resides in java.util and provides an external ordering, useful when the class does not implement Comparable or when a different ordering is needed.
Comparison with Spring’s @Order Annotation
In Spring, component ordering is controlled by the @Order annotation, which is processed by OrderComparator. The comparator ultimately delegates to Integer.compare, just like Zuul’s filter ordering.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
