Author: markt
Date: Fri Feb 19 19:30:53 2016
New Revision: 1731291
URL: http://svn.apache.org/viewvc?rev=1731291&view=rev
Log:
Refactor to use a local variable rather than a field.
Even after the cache is cleared it uses significant memory because of the size
the Map has grown to.
Modified:
tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java
tomcat/trunk/test/org/apache/catalina/startup/TestContextConfigAnnotation.java
tomcat/trunk/webapps/docs/changelog.xml
Modified: tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java?rev=1731291&r1=1731290&r2=1731291&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java Fri Feb 19
19:30:53 2016
@@ -222,14 +222,6 @@ public class ContextConfig implements Li
new HashMap<>();
/**
- * Cache of JavaClass objects (byte code) by fully qualified class name.
- * Only populated if it is necessary to scan the super types and interfaces
- * as part of the processing for {@link HandlesTypes}.
- */
- protected final Map<String,JavaClassCacheEntry> javaClassCache =
- new HashMap<>();
-
- /**
* Flag that indicates if at least one {@link HandlesTypes} entry is
present
* that represents an annotation.
*/
@@ -1141,13 +1133,15 @@ public class ContextConfig implements Li
if (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
// Step 4. Process /WEB-INF/classes for annotations and
// @HandlesTypes matches
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
+
if (ok) {
WebResource[] webResources =
context.getResources().listResources("/WEB-INF/classes");
for (WebResource webResource : webResources) {
processAnnotationsWebResource(webResource, webXml,
- webXml.isMetadataComplete());
+ webXml.isMetadataComplete(), javaClassCache);
}
}
@@ -1157,7 +1151,7 @@ public class ContextConfig implements Li
// container fragments)
if (ok) {
processAnnotations(
- orderedFragments, webXml.isMetadataComplete());
+ orderedFragments, webXml.isMetadataComplete(),
javaClassCache);
}
// Cache, if used, is no longer required so clear it
@@ -1899,7 +1893,7 @@ public class ContextConfig implements Li
}
protected void processAnnotations(Set<WebXml> fragments,
- boolean handlesTypesOnly) {
+ boolean handlesTypesOnly, Map<String,JavaClassCacheEntry>
javaClassCache) {
for(WebXml fragment : fragments) {
// Only need to scan for @HandlesTypes matches if any of the
// following are true:
@@ -1914,7 +1908,7 @@ public class ContextConfig implements Li
// no impact on distributable
annotations.setDistributable(true);
URL url = fragment.getURL();
- processAnnotationsUrl(url, annotations, htOnly);
+ processAnnotationsUrl(url, annotations, htOnly, javaClassCache);
Set<WebXml> set = new HashSet<>();
set.add(annotations);
// Merge annotations into fragment - fragment takes priority
@@ -1923,7 +1917,8 @@ public class ContextConfig implements Li
}
protected void processAnnotationsWebResource(WebResource webResource,
- WebXml fragment, boolean handlesTypesOnly) {
+ WebXml fragment, boolean handlesTypesOnly,
+ Map<String,JavaClassCacheEntry> javaClassCache) {
if (webResource.isDirectory()) {
WebResource[] webResources =
@@ -1936,13 +1931,13 @@ public class ContextConfig implements Li
webResource.getURL()));
}
for (WebResource r : webResources) {
- processAnnotationsWebResource(r, fragment,
handlesTypesOnly);
+ processAnnotationsWebResource(r, fragment,
handlesTypesOnly, javaClassCache);
}
}
} else if (webResource.isFile() &&
webResource.getName().endsWith(".class")) {
try (InputStream is = webResource.getInputStream()) {
- processAnnotationsStream(is, fragment, handlesTypesOnly);
+ processAnnotationsStream(is, fragment, handlesTypesOnly,
javaClassCache);
} catch (IOException e) {
log.error(sm.getString("contextConfig.inputStreamWebResource",
webResource.getWebappPath()),e);
@@ -1955,16 +1950,16 @@ public class ContextConfig implements Li
protected void processAnnotationsUrl(URL url, WebXml fragment,
- boolean handlesTypesOnly) {
+ boolean handlesTypesOnly, Map<String,JavaClassCacheEntry>
javaClassCache) {
if (url == null) {
// Nothing to do.
return;
} else if ("jar".equals(url.getProtocol())) {
- processAnnotationsJar(url, fragment, handlesTypesOnly);
+ processAnnotationsJar(url, fragment, handlesTypesOnly,
javaClassCache);
} else if ("file".equals(url.getProtocol())) {
try {
processAnnotationsFile(
- new File(url.toURI()), fragment, handlesTypesOnly);
+ new File(url.toURI()), fragment, handlesTypesOnly,
javaClassCache);
} catch (URISyntaxException e) {
log.error(sm.getString("contextConfig.fileUrl", url), e);
}
@@ -1977,7 +1972,7 @@ public class ContextConfig implements Li
protected void processAnnotationsJar(URL url, WebXml fragment,
- boolean handlesTypesOnly) {
+ boolean handlesTypesOnly, Map<String,JavaClassCacheEntry>
javaClassCache) {
try (Jar jar = JarFactory.newInstance(url)) {
if (log.isDebugEnabled()) {
@@ -1990,8 +1985,7 @@ public class ContextConfig implements Li
while (entryName != null) {
if (entryName.endsWith(".class")) {
try (InputStream is = jar.getEntryInputStream()) {
- processAnnotationsStream(
- is, fragment, handlesTypesOnly);
+ processAnnotationsStream(is, fragment,
handlesTypesOnly, javaClassCache);
} catch (IOException e) {
log.error(sm.getString("contextConfig.inputStreamJar",
entryName, url),e);
@@ -2010,7 +2004,7 @@ public class ContextConfig implements Li
protected void processAnnotationsFile(File file, WebXml fragment,
- boolean handlesTypesOnly) {
+ boolean handlesTypesOnly, Map<String,JavaClassCacheEntry>
javaClassCache) {
if (file.isDirectory()) {
// Returns null if directory is not readable
@@ -2022,12 +2016,12 @@ public class ContextConfig implements Li
}
for (String dir : dirs) {
processAnnotationsFile(
- new File(file,dir), fragment, handlesTypesOnly);
+ new File(file,dir), fragment, handlesTypesOnly,
javaClassCache);
}
}
} else if (file.getName().endsWith(".class") && file.canRead()) {
try (FileInputStream fis = new FileInputStream(file)) {
- processAnnotationsStream(fis, fragment, handlesTypesOnly);
+ processAnnotationsStream(fis, fragment, handlesTypesOnly,
javaClassCache);
} catch (IOException e) {
log.error(sm.getString("contextConfig.inputStreamFile",
file.getAbsolutePath()),e);
@@ -2040,12 +2034,12 @@ public class ContextConfig implements Li
protected void processAnnotationsStream(InputStream is, WebXml fragment,
- boolean handlesTypesOnly)
+ boolean handlesTypesOnly, Map<String,JavaClassCacheEntry>
javaClassCache)
throws ClassFormatException, IOException {
ClassParser parser = new ClassParser(is);
JavaClass clazz = parser.parse();
- checkHandlesTypes(clazz);
+ checkHandlesTypes(clazz, javaClassCache);
if (handlesTypesOnly) {
return;
@@ -2075,7 +2069,8 @@ public class ContextConfig implements Li
* for an annotation that matches {@link HandlesTypes}.
* @param javaClass the class to check
*/
- protected void checkHandlesTypes(JavaClass javaClass) {
+ protected void checkHandlesTypes(JavaClass javaClass,
+ Map<String,JavaClassCacheEntry> javaClassCache) {
// Skip this if we can
if (typeInitializerMap.size() == 0) {
@@ -2093,16 +2088,16 @@ public class ContextConfig implements Li
Class<?> clazz = null;
if (handlesTypesNonAnnotations) {
// This *might* be match for a HandlesType.
- populateJavaClassCache(className, javaClass);
+ populateJavaClassCache(className, javaClass, javaClassCache);
JavaClassCacheEntry entry = javaClassCache.get(className);
if (entry.getSciSet() == null) {
try {
- populateSCIsForCacheEntry(entry);
+ populateSCIsForCacheEntry(entry, javaClassCache);
} catch (StackOverflowError soe) {
throw new IllegalStateException(sm.getString(
"contextConfig.annotationsStackOverflow",
context.getName(),
- classHierarchyToString(className, entry)));
+ classHierarchyToString(className, entry,
javaClassCache)));
}
}
if (!entry.getSciSet().isEmpty()) {
@@ -2157,7 +2152,7 @@ public class ContextConfig implements Li
private String classHierarchyToString(String className,
- JavaClassCacheEntry entry) {
+ JavaClassCacheEntry entry, Map<String,JavaClassCacheEntry>
javaClassCache) {
JavaClassCacheEntry start = entry;
StringBuilder msg = new StringBuilder(className);
msg.append("->");
@@ -2180,7 +2175,8 @@ public class ContextConfig implements Li
return msg.toString();
}
- private void populateJavaClassCache(String className, JavaClass javaClass)
{
+ private void populateJavaClassCache(String className, JavaClass javaClass,
+ Map<String,JavaClassCacheEntry> javaClassCache) {
if (javaClassCache.containsKey(className)) {
return;
}
@@ -2188,14 +2184,15 @@ public class ContextConfig implements Li
// Add this class to the cache
javaClassCache.put(className, new JavaClassCacheEntry(javaClass));
- populateJavaClassCache(javaClass.getSuperclassName());
+ populateJavaClassCache(javaClass.getSuperclassName(), javaClassCache);
for (String iterface : javaClass.getInterfaceNames()) {
- populateJavaClassCache(iterface);
+ populateJavaClassCache(iterface, javaClassCache);
}
}
- private void populateJavaClassCache(String className) {
+ private void populateJavaClassCache(String className,
+ Map<String,JavaClassCacheEntry> javaClassCache) {
if (!javaClassCache.containsKey(className)) {
String name = className.replace('.', '/') + ".class";
try (InputStream is =
context.getLoader().getClassLoader().getResourceAsStream(name)) {
@@ -2204,7 +2201,7 @@ public class ContextConfig implements Li
}
ClassParser parser = new ClassParser(is);
JavaClass clazz = parser.parse();
- populateJavaClassCache(clazz.getClassName(), clazz);
+ populateJavaClassCache(clazz.getClassName(), clazz,
javaClassCache);
} catch (ClassFormatException e) {
log.debug(sm.getString("contextConfig.invalidSciHandlesTypes",
className), e);
@@ -2215,7 +2212,8 @@ public class ContextConfig implements Li
}
}
- private void populateSCIsForCacheEntry(JavaClassCacheEntry cacheEntry) {
+ private void populateSCIsForCacheEntry(JavaClassCacheEntry cacheEntry,
+ Map<String,JavaClassCacheEntry> javaClassCache) {
Set<ServletContainerInitializer> result = new HashSet<>();
// Super class
@@ -2232,7 +2230,7 @@ public class ContextConfig implements Li
// May be null of the class is not present or could not be loaded.
if (superClassCacheEntry != null) {
if (superClassCacheEntry.getSciSet() == null) {
- populateSCIsForCacheEntry(superClassCacheEntry);
+ populateSCIsForCacheEntry(superClassCacheEntry,
javaClassCache);
}
result.addAll(superClassCacheEntry.getSciSet());
}
@@ -2247,7 +2245,7 @@ public class ContextConfig implements Li
// so move along
if (interfaceEntry != null) {
if (interfaceEntry.getSciSet() == null) {
- populateSCIsForCacheEntry(interfaceEntry);
+ populateSCIsForCacheEntry(interfaceEntry, javaClassCache);
}
result.addAll(interfaceEntry.getSciSet());
}
@@ -2598,7 +2596,7 @@ public class ContextConfig implements Li
}
}
- private static class JavaClassCacheEntry {
+ static class JavaClassCacheEntry {
public final String superclassName;
public final String[] interfaceNames;
Modified:
tomcat/trunk/test/org/apache/catalina/startup/TestContextConfigAnnotation.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/startup/TestContextConfigAnnotation.java?rev=1731291&r1=1731290&r2=1731291&view=diff
==============================================================================
---
tomcat/trunk/test/org/apache/catalina/startup/TestContextConfigAnnotation.java
(original)
+++
tomcat/trunk/test/org/apache/catalina/startup/TestContextConfigAnnotation.java
Fri Feb 19 19:30:53 2016
@@ -19,7 +19,9 @@ package org.apache.catalina.startup;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.net.URL;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import javax.servlet.DispatcherType;
@@ -39,6 +41,7 @@ import org.junit.Test;
import org.apache.catalina.Context;
import org.apache.catalina.Loader;
import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.startup.ContextConfig.JavaClassCacheEntry;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.apache.tomcat.util.descriptor.web.ServletDef;
@@ -55,11 +58,12 @@ public class TestContextConfigAnnotation
@Test
public void testAnnotation() throws Exception {
WebXml webxml = new WebXml();
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
ContextConfig config = new ContextConfig();
File pFile = paramClassResource(
"org/apache/catalina/startup/ParamServlet");
assertTrue(pFile.exists());
- config.processAnnotationsFile(pFile, webxml, false);
+ config.processAnnotationsFile(pFile, webxml, false, javaClassCache);
ServletDef servletDef = webxml.getServlets().get("param");
assertNotNull(servletDef);
assertEquals("Hello", servletDef.getParameterMap().get("foo"));
@@ -81,6 +85,7 @@ public class TestContextConfigAnnotation
@Test
public void testOverwriteAnnotation() throws Exception {
WebXml webxml = new WebXml();
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
ServletDef servletDef = new ServletDef();
servletDef.setServletName("param");
servletDef.setServletClass("org.apache.catalina.startup.ParamServlet");
@@ -98,7 +103,7 @@ public class TestContextConfigAnnotation
File pFile = paramClassResource(
"org/apache/catalina/startup/ParamServlet");
assertTrue(pFile.exists());
- config.processAnnotationsFile(pFile, webxml, false);
+ config.processAnnotationsFile(pFile, webxml, false, javaClassCache);
assertEquals(servletDef, webxml.getServlets().get("param"));
@@ -121,16 +126,17 @@ public class TestContextConfigAnnotation
@Test
public void testNoMapping() throws Exception {
WebXml webxml = new WebXml();
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
ContextConfig config = new ContextConfig();
File pFile = paramClassResource(
"org/apache/catalina/startup/NoMappingParamServlet");
assertTrue(pFile.exists());
- config.processAnnotationsFile(pFile, webxml, false);
+ config.processAnnotationsFile(pFile, webxml, false, javaClassCache);
ServletDef servletDef = webxml.getServlets().get("param1");
assertNull(servletDef);
webxml.addServletMapping("/param", "param1");
- config.processAnnotationsFile(pFile, webxml, false);
+ config.processAnnotationsFile(pFile, webxml, false, javaClassCache);
servletDef = webxml.getServlets().get("param1");
assertNull(servletDef);
@@ -139,6 +145,7 @@ public class TestContextConfigAnnotation
@Test
public void testSetupWebXMLNoMapping() throws Exception {
WebXml webxml = new WebXml();
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
ServletDef servletDef = new ServletDef();
servletDef.setServletName("param1");
servletDef.setServletClass(
@@ -151,7 +158,7 @@ public class TestContextConfigAnnotation
File pFile = paramClassResource(
"org/apache/catalina/startup/NoMappingParamServlet");
assertTrue(pFile.exists());
- config.processAnnotationsFile(pFile, webxml, false);
+ config.processAnnotationsFile(pFile, webxml, false, javaClassCache);
assertEquals("tomcat", servletDef.getParameterMap().get("foo"));
assertEquals("World!", servletDef.getParameterMap().get("bar"));
ServletDef servletDef1 = webxml.getServlets().get("param1");
@@ -162,12 +169,13 @@ public class TestContextConfigAnnotation
@Test
public void testDuplicateMapping() throws Exception {
WebXml webxml = new WebXml();
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
ContextConfig config = new ContextConfig();
File pFile = paramClassResource(
"org/apache/catalina/startup/DuplicateMappingParamServlet");
assertTrue(pFile.exists());
try {
- config.processAnnotationsFile(pFile, webxml, false);
+ config.processAnnotationsFile(pFile, webxml, false,
javaClassCache);
fail();
} catch (IllegalArgumentException ex) {
// ignore
@@ -179,13 +187,14 @@ public class TestContextConfigAnnotation
@Test
public void testFilterMapping() throws Exception {
WebXml webxml = new WebXml();
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
ContextConfig config = new ContextConfig();
File sFile = paramClassResource(
"org/apache/catalina/startup/ParamServlet");
- config.processAnnotationsFile(sFile, webxml, false);
+ config.processAnnotationsFile(sFile, webxml, false, javaClassCache);
File fFile = paramClassResource(
"org/apache/catalina/startup/ParamFilter");
- config.processAnnotationsFile(fFile, webxml, false);
+ config.processAnnotationsFile(fFile, webxml, false, javaClassCache);
FilterDef fdef = webxml.getFilters().get("paramFilter");
assertNotNull(fdef);
assertEquals("Servlet says: ",fdef.getParameterMap().get("message"));
@@ -194,6 +203,7 @@ public class TestContextConfigAnnotation
@Test
public void testOverwriteFilterMapping() throws Exception {
WebXml webxml = new WebXml();
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
FilterDef filterDef = new FilterDef();
filterDef.setFilterName("paramFilter");
filterDef.setFilterClass("org.apache.catalina.startup.ParamFilter");
@@ -214,10 +224,10 @@ public class TestContextConfigAnnotation
ContextConfig config = new ContextConfig();
File sFile = paramClassResource(
"org/apache/catalina/startup/ParamServlet");
- config.processAnnotationsFile(sFile, webxml, false);
+ config.processAnnotationsFile(sFile, webxml, false, javaClassCache);
File fFile = paramClassResource(
"org/apache/catalina/startup/ParamFilter");
- config.processAnnotationsFile(fFile, webxml, false);
+ config.processAnnotationsFile(fFile, webxml, false, javaClassCache);
FilterDef fdef = webxml.getFilters().get("paramFilter");
assertNotNull(fdef);
assertEquals(filterDef,fdef);
@@ -249,12 +259,13 @@ public class TestContextConfigAnnotation
@Test
public void testDuplicateFilterMapping() throws Exception {
WebXml webxml = new WebXml();
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
ContextConfig config = new ContextConfig();
File pFile = paramClassResource(
"org/apache/catalina/startup/DuplicateMappingParamFilter");
assertTrue(pFile.exists());
try {
- config.processAnnotationsFile(pFile, webxml, false);
+ config.processAnnotationsFile(pFile, webxml, false,
javaClassCache);
fail();
} catch (IllegalArgumentException ex) {
// ignore
@@ -265,6 +276,7 @@ public class TestContextConfigAnnotation
@Test
public void testCheckHandleTypes() throws Exception {
+ Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
ContextConfig config = new ContextConfig();
config.handlesTypesAnnotations = true;
config.handlesTypesNonAnnotations = true;
@@ -296,13 +308,13 @@ public class TestContextConfigAnnotation
WebXml ignore = new WebXml();
File file = paramClassResource(
"org/apache/catalina/startup/ParamServlet");
- config.processAnnotationsFile(file, ignore, false);
+ config.processAnnotationsFile(file, ignore, false, javaClassCache);
file = paramClassResource("org/apache/catalina/startup/ParamFilter");
- config.processAnnotationsFile(file, ignore, false);
+ config.processAnnotationsFile(file, ignore, false, javaClassCache);
file = paramClassResource("org/apache/catalina/startup/TesterServlet");
- config.processAnnotationsFile(file, ignore, false);
+ config.processAnnotationsFile(file, ignore, false, javaClassCache);
file = paramClassResource("org/apache/catalina/startup/TestListener");
- config.processAnnotationsFile(file, ignore, false);
+ config.processAnnotationsFile(file, ignore, false, javaClassCache);
// Check right number of classes were noted to be handled
assertEquals(0, config.initializerClassMap.get(sciNone).size());
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1731291&r1=1731290&r2=1731291&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Feb 19 19:30:53 2016
@@ -108,6 +108,9 @@
effective web.xml. Components needing access to configuration
information may access it via the Servlet API. (markt)
</fix>
+ <fix>
+ Refactor JAR scanning to reduce memory footprint. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Coyote">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]