Skip to content

Commit 7b08fee

Browse files
committed
Make jar caching configurable through setUseCaches
Closes gh-34678
1 parent 743f326 commit 7b08fee

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
lines changed

spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java

+36-7
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@
215215
*/
216216
public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
217217

218+
private static final Resource[] EMPTY_RESOURCE_ARRAY = {};
219+
218220
private static final Log logger = LogFactory.getLog(PathMatchingResourcePatternResolver.class);
219221

220222
/**
@@ -257,6 +259,8 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
257259

258260
private PathMatcher pathMatcher = new AntPathMatcher();
259261

262+
private boolean useCaches = true;
263+
260264
private final Map<String, Resource[]> rootDirCache = new ConcurrentHashMap<>();
261265

262266
private final Map<String, NavigableSet<String>> jarEntriesCache = new ConcurrentHashMap<>();
@@ -331,6 +335,22 @@ public PathMatcher getPathMatcher() {
331335
return this.pathMatcher;
332336
}
333337

338+
/**
339+
* Specify whether this resolver should use jar caches. Default is {@code true}.
340+
* <p>Switch this flag to {@code false} in order to avoid any jar caching, at
341+
* the {@link JarURLConnection} level as well as within this resolver instance.
342+
* <p>Note that {@link JarURLConnection#setDefaultUseCaches} can be turned off
343+
* independently. This resolver-level setting is designed to only enforce
344+
* {@code JarURLConnection#setUseCaches(false)} if necessary but otherwise
345+
* leaves the JVM-level default in place.
346+
* @since 6.1.19
347+
* @see JarURLConnection#setUseCaches
348+
* @see #clearCache()
349+
*/
350+
public void setUseCaches(boolean useCaches) {
351+
this.useCaches = useCaches;
352+
}
353+
334354

335355
@Override
336356
public Resource getResource(String location) {
@@ -354,7 +374,7 @@ public Resource[] getResources(String locationPattern) throws IOException {
354374
// all class path resources with the given name
355375
Collections.addAll(resources, findAllClassPathResources(locationPatternWithoutPrefix));
356376
}
357-
return resources.toArray(new Resource[0]);
377+
return resources.toArray(EMPTY_RESOURCE_ARRAY);
358378
}
359379
else {
360380
// Generally only look for a pattern after a prefix here,
@@ -398,7 +418,7 @@ protected Resource[] findAllClassPathResources(String location) throws IOExcepti
398418
if (logger.isTraceEnabled()) {
399419
logger.trace("Resolved class path location [" + path + "] to resources " + result);
400420
}
401-
return result.toArray(new Resource[0]);
421+
return result.toArray(EMPTY_RESOURCE_ARRAY);
402422
}
403423

404424
/**
@@ -535,7 +555,9 @@ protected void addClassPathManifestEntries(Set<Resource> result) {
535555
Set<ClassPathManifestEntry> entries = this.manifestEntriesCache;
536556
if (entries == null) {
537557
entries = getClassPathManifestEntries();
538-
this.manifestEntriesCache = entries;
558+
if (this.useCaches) {
559+
this.manifestEntriesCache = entries;
560+
}
539561
}
540562
for (ClassPathManifestEntry entry : entries) {
541563
if (!result.contains(entry.resource()) &&
@@ -687,7 +709,9 @@ else if (commonPrefix.equals(rootDirPath)) {
687709
if (rootDirResources == null) {
688710
// Lookup for specific directory, creating a cache entry for it.
689711
rootDirResources = getResources(rootDirPath);
690-
this.rootDirCache.put(rootDirPath, rootDirResources);
712+
if (this.useCaches) {
713+
this.rootDirCache.put(rootDirPath, rootDirResources);
714+
}
691715
}
692716
}
693717

@@ -719,7 +743,7 @@ else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
719743
if (logger.isTraceEnabled()) {
720744
logger.trace("Resolved location pattern [" + locationPattern + "] to resources " + result);
721745
}
722-
return result.toArray(new Resource[0]);
746+
return result.toArray(EMPTY_RESOURCE_ARRAY);
723747
}
724748

725749
/**
@@ -840,6 +864,9 @@ protected Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource,
840864

841865
if (con instanceof JarURLConnection jarCon) {
842866
// Should usually be the case for traditional JAR files.
867+
if (!this.useCaches) {
868+
jarCon.setUseCaches(false);
869+
}
843870
try {
844871
jarFile = jarCon.getJarFile();
845872
jarFileUrl = jarCon.getJarFileURL().toExternalForm();
@@ -903,8 +930,10 @@ protected Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource,
903930
}
904931
}
905932
}
906-
// Cache jar entries in TreeSet for efficient searching on re-encounter.
907-
this.jarEntriesCache.put(jarFileUrl, entriesCache);
933+
if (this.useCaches) {
934+
// Cache jar entries in TreeSet for efficient searching on re-encounter.
935+
this.jarEntriesCache.put(jarFileUrl, entriesCache);
936+
}
908937
return result;
909938
}
910939
finally {

spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -132,6 +132,7 @@ void encodedHashtagInPath() throws IOException {
132132
Path rootDir = Paths.get("src/test/resources/custom%23root").toAbsolutePath();
133133
URL root = new URL("file:" + rootDir + "/");
134134
resolver = new PathMatchingResourcePatternResolver(new DefaultResourceLoader(new URLClassLoader(new URL[] {root})));
135+
resolver.setUseCaches(false);
135136
assertExactFilenames("classpath*:scanned/*.txt", "resource#test1.txt", "resource#test2.txt");
136137
}
137138

0 commit comments

Comments
 (0)