Performance improvements in ShallowEtagHeaderFilter

Prior to this change, the ShallowEtagHeaderFilter would use a
ResizableByteArrayOutputStream to internally write data and calculate
the ETag. While that implementation is faster than the regular
ByteArrayOutputStream (since it has a better strategy for growing the
internal buffer), a lot of buffer copying/writing still happens.

This change adds a new FastByteArrayOutputStream implementation that
internally uses a LinkedList<Byte[]> to store the content. So when
writing bytes to that OutputStream implementation, new byte[] are
added to the list when the previous ones are full. This saves most
of the instantiating/copying operations.

Note that new methods were added in DigestUtils to allow usage of
Streams instead of byte[], which is more efficient in our case.

Fixes #653

Issue: SPR-12081
This commit is contained in:
Craig Andrews
2015-01-07 16:53:09 +01:00
committed by Brian Clozel
parent 40cd1be14c
commit 213a3fd779
7 changed files with 909 additions and 44 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.web.filter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@@ -51,15 +52,15 @@ public class ShallowEtagHeaderFilterTests {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels");
MockHttpServletResponse response = new MockHttpServletResponse();
assertTrue(filter.isEligibleForEtag(request, response, 200, new byte[0]));
assertFalse(filter.isEligibleForEtag(request, response, 300, new byte[0]));
assertTrue(filter.isEligibleForEtag(request, response, 200, new ByteArrayInputStream(new byte[0])));
assertFalse(filter.isEligibleForEtag(request, response, 300, new ByteArrayInputStream(new byte[0])));
request = new MockHttpServletRequest("POST", "/hotels");
assertFalse(filter.isEligibleForEtag(request, response, 200, new byte[0]));
assertFalse(filter.isEligibleForEtag(request, response, 200, new ByteArrayInputStream(new byte[0])));
request = new MockHttpServletRequest("POST", "/hotels");
request.addHeader("Cache-Control","must-revalidate, no-store");
assertFalse(filter.isEligibleForEtag(request, response, 200, new byte[0]));
assertFalse(filter.isEligibleForEtag(request, response, 200, new ByteArrayInputStream(new byte[0])));
}
@Test