Skip to content

Honor BeanDefinition order attribute for DispatcherServlet strategies#36739

Open
daguimu wants to merge 5 commits intospring-projects:mainfrom
daguimu:fix/dispatcher-strategy-order-attribute-36637
Open

Honor BeanDefinition order attribute for DispatcherServlet strategies#36739
daguimu wants to merge 5 commits intospring-projects:mainfrom
daguimu:fix/dispatcher-strategy-order-attribute-36637

Conversation

@daguimu
Copy link
Copy Markdown
Contributor

@daguimu daguimu commented May 1, 2026

Problem

DispatcherServlet detects four kinds of strategy beans (HandlerMapping, HandlerAdapter, HandlerExceptionResolver, ViewResolver) by type and keeps each list sorted. The sort calls AnnotationAwareOrderComparator.sort(list) directly on the matched bean instances, which only consults @Order on the bean class and the Ordered interface.

Setting the order programmatically — via BeanRegistrar.Spec#order(int), the order parameter on GenericApplicationContext#registerBean(...), or AbstractBeanDefinition#ORDER_ATTRIBUTE directly on a bean definition — has no effect on these strategy lists, even though the same attribute is honored for sorted dependency injection through DefaultListableBeanFactory.FactoryAwareOrderSourceProvider.

Root cause

AnnotationAwareOrderComparator.sort(List) runs without an OrderSourceProvider. With no source provider, the comparator never reaches the bean definition and cannot read ORDER_ATTRIBUTE.

Fix

Add a private helper sortStrategyBeans that sorts the matched list using AnnotationAwareOrderComparator.INSTANCE.withSourceProvider(...). The BeanDefinitionOrderSourceProvider mirrors FactoryAwareOrderSourceProvider exactly:

  • Looks up the merged BeanDefinition via ConfigurableApplicationContext.getBeanFactory().getMergedBeanDefinition(...) (which already walks the parent BeanFactory chain).
  • Adds the ORDER_ATTRIBUTE value as an Ordered source when present and Integer.
  • Adds the factory method as a source for RootBeanDefinition instances (so @Order on a @Bean factory method works).
  • Adds the declared target type as a source when distinct from the bean's runtime class.
  • Throws IllegalStateException for a non-Integer ORDER_ATTRIBUTE, matching the bean factory's fail-fast behavior.

The helper is applied at all four strategy-detection sites. Beans without ORDER_ATTRIBUTE see no behavior change — the comparator still falls back to @Order / Ordered.

Tests Added

Change Point Test
sortStrategyBeans honors ORDER_ATTRIBUTE detectsHandlerMappingsOrderedByBeanDefinitionOrderAttribute
ORDER_ATTRIBUTE overrides class-level @Order beanDefinitionOrderAttributeOverridesAnnotationOrderForHandlerMappings
ORDER_ATTRIBUTE resolved across parent contexts handlerMappingOrderFromBeanDefinitionInheritsAcrossParentContext
Non-Integer ORDER_ATTRIBUTE is rejected nonIntegerOrderAttributeIsRejected

The tests exercise the change through getHandlerMappings() but cover the shared helper used by all four strategies. The full :spring-webmvc:test suite passes.

Impact

  • Scope: spring-webmvc only; private API, no public surface added.
  • Behavior change is strictly additive for the common case.
  • Fail-fast path is only reachable when user code sets ORDER_ATTRIBUTE to a non-Integer directly; public APIs only accept int/Integer.
  • Default-strategy fallback (DispatcherServlet.properties) is unaffected.
  • WebFlux's DispatcherHandler and OncePerRequestFilter ordering are out of scope.

Closes gh-36637

bclozel added 4 commits April 30, 2026 15:30
Prior to this commit, the `resolveUrlPath` implementation for the
`LiteWebJarsResourceResolver` would always delegate to the resource
chain once the versioned webjar folder has been resolved.

While this aligns with the `ResourceResolver` contract and the fact that
the resource chain does not resolve directories, here the WebJar locator
does support such use cases and we shouldn't get in the way here.

This commit falls back to the resolved versioned WebJar path if no
resource could be resolved and the path ends with "/".

Fixes spring-projectsgh-36726
Prior to this commit, MIME types with parameter values that contain a
quoted pair would sometimes fail and parse an incomplete parameter
value.

This commit ensures that the quoted section of the parameter value is
correctly handled.

Fixes spring-projectsgh-36730
@daguimu daguimu force-pushed the fix/dispatcher-strategy-order-attribute-36637 branch from 68f63cd to c4594f4 Compare May 1, 2026 04:19
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label May 1, 2026
…trategies

The strategy detection in DispatcherServlet (HandlerMappings, HandlerAdapters,
HandlerExceptionResolvers, ViewResolvers) sorted matched beans with
AnnotationAwareOrderComparator.sort(...) directly. That comparator only sees
the bean instances and falls back to @order annotation or the Ordered interface,
ignoring an order attribute set on the merged bean definition.

As a result, ordering bean definitions programmatically — via
BeanRegistrar.Spec#order(int), GenericApplicationContext.registerBean's order
parameter, or AbstractBeanDefinition#ORDER_ATTRIBUTE directly — had no effect
on these strategy lists, even though the same attribute is honored for sorted
dependency injection (DefaultListableBeanFactory's FactoryAwareOrderSourceProvider).

Sort each strategy list with a comparator that wraps an OrderSourceProvider.
The provider mirrors FactoryAwareOrderSourceProvider: it resolves the merged
BeanDefinition and exposes its ORDER_ATTRIBUTE, factory method, and declared
target type as ordering sources, leaving @Order/Ordered fallback to the
comparator. Non-Integer ORDER_ATTRIBUTE values are rejected with
IllegalStateException, matching the bean factory's existing behavior.
Behavior is unchanged for beans that do not declare ORDER_ATTRIBUTE.

Closes spring-projectsgh-36637

Signed-off-by: daguimu <daguimu.geek@gmail.com>
@daguimu daguimu force-pushed the fix/dispatcher-strategy-order-attribute-36637 branch from c4594f4 to 7a05a9e Compare May 1, 2026 05:05
@rstoyanchev
Copy link
Copy Markdown
Contributor

rstoyanchev commented May 2, 2026

Note that we've had to re-write commits in main and 7.0.x over the past 2 days after erroneous merge that this PR was based on. The PR needs to be handled with care focusing on just the one commit 7a05a9e and ignoring the other 4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged or decided on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting order programmatically on OncePerRequestFilter or HandlerExceptionResolver beans using BeanRegistrar or GenericApplicationContext does not work

4 participants