Optimize MediaType parsing

Prior to this commit, `MediaType.parseMediaType` would already rely on
the internal LRU cache in `MimeTypeUtils` for better performance. With
that optimization, the parsing of raw media types is skipped for cached
elements.
But still, `MediaType.parseMediaType` would first get a cached
`MimeType` instance from that cache and then instantiate a
`new MediaType(type, subtype, parameters)`. This constructor not only
replays the `MimeType` checks on type/subtyme tokens and parameters, but
it also performs `MediaType`-specific checks on parameters.
Such checks are not required, as we're using an existing `MimeType`
instance in the first place.

This commit adds a new protected copy constructor (skipping checks) in
`MimeType` and uses it in `MediaType.parseMediaType` as a result.

This yields interesting performance improvements, with +400% throughput
and -40% allocation/call in benchmarks. This commit also introduces a
new JMH benchmark for future optimization work.

Closes gh-24769
This commit is contained in:
Brian Clozel
2020-05-13 21:36:06 +02:00
parent 67547e61c6
commit 612a63c0f1
3 changed files with 141 additions and 2 deletions

View File

@@ -190,6 +190,18 @@ public class MimeType implements Comparable<MimeType>, Serializable {
}
}
/**
* Copy-constructor that copies the type, subtype and parameters of the given {@code MimeType},
* skipping checks performed in other constructors.
* @param other the other MimeType
*/
protected MimeType(MimeType other) {
this.type = other.type;
this.subtype = other.subtype;
this.parameters = other.parameters;
this.toStringValue = other.toStringValue;
}
/**
* Checks the given token string for illegal characters, as defined in RFC 2616,
* section 2.2.
@@ -197,7 +209,7 @@ public class MimeType implements Comparable<MimeType>, Serializable {
* @see <a href="https://tools.ietf.org/html/rfc2616#section-2.2">HTTP 1.1, section 2.2</a>
*/
private void checkToken(String token) {
for (int i = 0; i < token.length(); i++ ) {
for (int i = 0; i < token.length(); i++) {
char ch = token.charAt(i);
if (!TOKEN.get(ch)) {
throw new IllegalArgumentException("Invalid token character '" + ch + "' in token \"" + token + "\"");