How Does Spring Security Manage Built‑In Filter Order? A Deep Dive
This article explains how Spring Security’s HttpSecurity class maintains the order of its built‑in filters using FilterOrderRegistration, demonstrates the registration and retrieval logic with code examples, and clarifies how duplicate orders are resolved during filter sorting.
Spring Security’s HttpSecurity contains a member variable FilterOrderRegistration, which acts as a registry for built‑in filters. The registry holds a map filterToOrder that records each filter’s order and the step size between them.
Built‑in Filter Order
The following code copies the registration map and prints the filters in order:
CopyFilterOrderRegistration filterOrderRegistration = new CopyFilterOrderRegistration();
// Get built‑in filters (method not provided)
Map<String, Integer> filterToOrder = filterOrderRegistration.getFilterToOrder();
TreeMap<Integer, String> orderToFilter = new TreeMap<>();
filterToOrder.forEach((name, order) -> orderToFilter.put(order, name));
orderToFilter.forEach((order, name) -> System.out.println(" 顺序:" + order + " 类名:" + name));The printed result shows that the relative positions of built‑in filters are fixed: the first step is 200, while all subsequent steps are 100.
Built‑in filters are only pre‑positioned; they become effective only when HttpSecurity explicitly adds them via the addFilterXXXX series of methods.
Registration Logic
FilterOrderRegistrationprovides a put method to register a filter with a specific position:
void put(Class<? extends Filter> filter, int position) {
String className = filter.getName();
// Ignore if already registered
if (this.filterToOrder.containsKey(className)) {
return;
}
// Register the order
this.filterToOrder.put(className, position);
}From this we can conclude:
The 34 built‑in filters have immutable order numbers.
New filters must have fully qualified class names that do not duplicate built‑in ones.
New filters may share the same order number as built‑in filters.
Retrieving a Filter’s Order
FilterOrderRegistrationalso offers a getOrder method that walks up the class hierarchy to find an order value:
Integer getOrder(Class<?> clazz) {
while (clazz != null) {
Integer result = this.filterToOrder.get(clazz.getName());
if (result != null) {
return result;
}
clazz = clazz.getSuperclass();
}
return null;
}HttpSecurity’s Filter Management Methods
The private method addFilterAtOffsetOf calculates a new filter’s order based on a registered filter and an offset, then adds it to the internal list:
private HttpSecurity addFilterAtOffsetOf(Filter filter, int offset, Class<? extends Filter> registeredFilter) {
int order = this.filterOrders.getOrder(registeredFilter) + offset;
this.filters.add(new OrderedFilter(filter, order));
this.filterOrders.put(filter.getClass(), order);
return this;
}Remember that registeredFilter must already be present in FilterOrderRegistration .
Other convenience methods delegate to this logic. For example, addFilterAfter simply calls addFilterAtOffsetOf(filter, 1, afterFilter), placing the new filter one position after the specified one.
public HttpSecurity addFilterAfter(Filter filter, Class<? extends Filter> afterFilter) {
return addFilterAtOffsetOf(filter, 1, afterFilter);
}The generic addFilter method requires the filter to already have a registered order; otherwise it throws an exception, encouraging the use of addFilterBefore or addFilterAfter instead.
public HttpSecurity addFilter(Filter filter) {
Integer order = this.filterOrders.getOrder(filter.getClass());
if (order == null) {
throw new IllegalArgumentException("The Filter class " + filter.getClass().getName() + " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead.");
}
this.filters.add(new OrderedFilter(filter, order));
return this;
}What Happens with Duplicate Orders?
If two filters are registered with the same order number, Spring Security sorts them by the natural order of the numbers; when numbers are equal, the filter added earlier (lower index) appears first.
// filters list
private List<OrderedFilter> filters = new ArrayList<>();
// sort
this.filters.sort(OrderComparator.INSTANCE);The OrderComparator performs a numeric comparison, and for equal numbers it preserves insertion order, so the first added filter takes precedence.
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.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
