diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java index 3315e5b2df9..eb4f5b74aef 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java @@ -235,9 +235,6 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol private static final Predicate isNotSystemModule = resolvedModule -> !systemModuleNames.contains(resolvedModule.name()); - @Nullable - private static Set classPathManifestEntriesCache; - @Nullable private static Method equinoxResolveMethod; @@ -261,7 +258,10 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol private final Map rootDirCache = new ConcurrentHashMap<>(); - private final Map> jarEntryCache = new ConcurrentHashMap<>(); + private final Map> jarEntriesCache = new ConcurrentHashMap<>(); + + @Nullable + private volatile Set manifestEntriesCache; /** @@ -377,7 +377,8 @@ public Resource[] getResources(String locationPattern) throws IOException { */ public void clearCache() { this.rootDirCache.clear(); - this.jarEntryCache.clear(); + this.jarEntriesCache.clear(); + this.manifestEntriesCache = null; } @@ -530,10 +531,10 @@ protected void addAllClassLoaderJarRoots(@Nullable ClassLoader classLoader, Set< * @since 4.3 */ protected void addClassPathManifestEntries(Set result) { - Set entries = classPathManifestEntriesCache; + Set entries = this.manifestEntriesCache; if (entries == null) { entries = getClassPathManifestEntries(); - classPathManifestEntriesCache = entries; + this.manifestEntriesCache = entries; } for (ClassPathManifestEntry entry : entries) { if (!result.contains(entry.resource()) && @@ -544,7 +545,7 @@ protected void addClassPathManifestEntries(Set result) { } private Set getClassPathManifestEntries() { - Set manifestEntries = new HashSet<>(); + Set manifestEntries = new LinkedHashSet<>(); Set seen = new HashSet<>(); try { String paths = System.getProperty("java.class.path"); @@ -578,9 +579,9 @@ private Set getClassPathManifestEntriesFromJar(File jar) File parent = jar.getAbsoluteFile().getParentFile(); try (JarFile jarFile = new JarFile(jar)) { Manifest manifest = jarFile.getManifest(); - Attributes attributes = (manifest != null) ? manifest.getMainAttributes() : null; - String classPath = (attributes != null) ? attributes.getValue(Name.CLASS_PATH) : null; - Set manifestEntries = new HashSet<>(); + Attributes attributes = (manifest != null ? manifest.getMainAttributes() : null); + String classPath = (attributes != null ? attributes.getValue(Name.CLASS_PATH) : null); + Set manifestEntries = new LinkedHashSet<>(); if (StringUtils.hasLength(classPath)) { StringTokenizer tokenizer = new StringTokenizer(classPath); while (tokenizer.hasMoreTokens()) { @@ -806,11 +807,11 @@ protected Set doFindPathMatchingJarResources(Resource rootDirResource, if (separatorIndex != -1) { jarFileUrl = urlFile.substring(0, separatorIndex); rootEntryPath = urlFile.substring(separatorIndex + 2); // both separators are 2 chars - NavigableSet entryCache = this.jarEntryCache.get(jarFileUrl); - if (entryCache != null) { + NavigableSet entriesCache = this.jarEntriesCache.get(jarFileUrl); + if (entriesCache != null) { Set result = new LinkedHashSet<>(64); // Search sorted entries from first entry with rootEntryPath prefix - for (String entryPath : entryCache.tailSet(rootEntryPath, false)) { + for (String entryPath : entriesCache.tailSet(rootEntryPath, false)) { if (!entryPath.startsWith(rootEntryPath)) { // We are beyond the potential matches in the current TreeSet. break; @@ -870,11 +871,9 @@ protected Set doFindPathMatchingJarResources(Resource rootDirResource, rootEntryPath = rootEntryPath + "/"; } Set result = new LinkedHashSet<>(64); - NavigableSet entryCache = new TreeSet<>(); - for (Enumeration entries = jarFile.entries(); entries.hasMoreElements(); ) { - JarEntry entry = entries.nextElement(); - String entryPath = entry.getName(); - entryCache.add(entryPath); + NavigableSet entriesCache = new TreeSet<>(); + for (String entryPath : jarFile.stream().map(JarEntry::getName).sorted().toList()) { + entriesCache.add(entryPath); if (entryPath.startsWith(rootEntryPath)) { String relativePath = entryPath.substring(rootEntryPath.length()); if (getPathMatcher().match(subPattern, relativePath)) { @@ -883,7 +882,7 @@ protected Set doFindPathMatchingJarResources(Resource rootDirResource, } } // Cache jar entries in TreeSet for efficient searching on re-encounter. - this.jarEntryCache.put(jarFileUrl, entryCache); + this.jarEntriesCache.put(jarFileUrl, entriesCache); return result; } finally { @@ -1236,9 +1235,9 @@ private static Resource createAlternative(String path) { } } - private static Resource asJarFileResource(String path) - throws MalformedURLException { + private static Resource asJarFileResource(String path) throws MalformedURLException { return new UrlResource(JARFILE_URL_PREFIX + path + ResourceUtils.JAR_URL_SEPARATOR); } } + }