codeconsole opened a new pull request, #16149:
URL: https://github.com/apache/grails-core/pull/16149
Reduces per-request work across the request path, and adds an opt-in JMH
module so the
changes are measured rather than asserted.
## Measured
Before/after on the same machine and JDK (21.0.7, Apple M4 Max), 2 forks x
(5 warmup +
5 measurement):
| Benchmark | before ns/op | after ns/op | |
|---|---:|---:|---|
| `ControllerActionBenchmark.plainAction` | 34.8 | **3.6** | −89.7% |
| `InterceptorChainBenchmark.oneInterceptorNoOpRegistry` | 295.3 | **127.5**
| −56.8% |
| `InterceptorChainBenchmark.threeInterceptorsNoOpRegistry` | 1116.9 |
**545.6** | −51.2% |
| `GrailsWebRequestBenchmark.construct` | 16.3 | **11.7** | −28.1% |
| `UrlMappingBenchmark.matchRestfulUriCacheMiss` | 1550.0 | **1287.8** |
−16.9% |
| `UrlMappingBenchmark.matchDefaultMappingUriCacheMiss` | 1881.3 |
**1595.4** | −15.2% |
Nothing regressed. Run them with:
```
./gradlew :grails-web-benchmarks:jmh
```
## What changed
- **Multipart**: `request` is no longer replaced by the resolved
`MultipartHttpServletRequest`.
It is discovered from the wrapper chain instead, so the security and
method-override
wrappers survive. `request.getFile(..)`, `params.myFile` and `byte[]`
binding are unchanged.
- **Application attributes** were built per request through a reflective
constructor, discarding
the five beans they cache. Now resolved once per servlet context.
- **Handler chain** assembly delegates to `AbstractHandlerMapping` instead
of duplicating it, so
Grails-mapped requests no longer miss what Spring adds there (currently
the API version
deprecation interceptor). Two per-request interceptor allocations removed.
- **Interceptors** no longer allocate a JDK dynamic proxy per phase: the `as
BooleanSupplier`
coercion ran even when the ObservationRegistry is a no-op.
- **Generated actions** no longer carry allowed-methods bookkeeping when the
controller declares
no `allowedMethods`. A plain action went from 8 request-attribute
operations to none. It was
also being emitted twice into the same method.
- **Data binding** resolves its collaborators once per `ApplicationContext`,
and caches the
negative result of the whitelist field lookup, which previously rebuilt a
`NoSuchFieldException`
on every bind for untransformed classes.
- **Redirect / render** cache the controller namespace, the redirector and
the view resolver
instead of resolving them per call.
- **URL matching** skips candidate patterns whose segment count rules them
out, before any regex
runs. Candidates are skipped, never reordered, so precedence is unchanged.
- Deletes unreachable multipart resolution in `DefaultUrlMappingInfo`, and
repairs a
`SpringSecurityUtils` branch that read an attribute only that dead code
ever wrote.
## Behaviour changes
Documented in the 8.0 upgrade guide, sections 45 and 46:
- `request instanceof MultipartHttpServletRequest` and casts to it no longer
work. The file
methods are unaffected.
- API versioning headers (`spring.mvc.apiversion.*`) are now emitted for
Grails-mapped requests.
- The `LocaleContext` is restored rather than cleared at the end of a
request.
- `GrailsWebRequest.getCurrentRequest()` is deprecated in favour of
`getRequest()`. Tests that
stubbed it need updating; `getRequest()` is `final` on Spring's
`ServletRequestAttributes`, so
that was the only stubbable accessor.
## Limitations
- Only the benchmarks above are measured. The interceptor, codegen and data
binding changes are
additionally evidenced by bytecode (proxy allocations gone, attribute
operations gone), but the
redirect/render caches have no number.
- This does **not** address the oversized-upload half of #16145 — that needs
early multipart
resolution, which #16146 provides. The two overlap; see the discussion
there.
- `collectControllerMappings` remains the largest cost on the path
(~360-1200 ns per request,
against 2.5 ns for a cached URL match). Addressed separately.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]