diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java index 39b7287a793..2aed7cc6967 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java @@ -361,12 +361,22 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { * @throws IOException if thrown from URLConnection methods */ protected void customizeConnection(URLConnection con) throws IOException { - ResourceUtils.useCachesIfNecessary(con); + useCachesIfNecessary(con); if (con instanceof HttpURLConnection httpCon) { customizeConnection(httpCon); } } + /** + * Apply {@link URLConnection#setUseCaches useCaches} if necessary. + * @param con the URLConnection to customize + * @since 6.2.10 + * @see ResourceUtils#useCachesIfNecessary(URLConnection) + */ + void useCachesIfNecessary(URLConnection con) { + ResourceUtils.useCachesIfNecessary(con); + } + /** * Customize the given {@link HttpURLConnection} before fetching the resource. *
Can be overridden in subclasses for configuring request headers and timeouts. diff --git a/spring-core/src/main/java/org/springframework/core/io/FileUrlResource.java b/spring-core/src/main/java/org/springframework/core/io/FileUrlResource.java index 300b5be4a3f..1878432af63 100644 --- a/spring-core/src/main/java/org/springframework/core/io/FileUrlResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/FileUrlResource.java @@ -109,7 +109,9 @@ public class FileUrlResource extends UrlResource implements WritableResource { @Override public Resource createRelative(String relativePath) throws MalformedURLException { - return new FileUrlResource(createRelativeURL(relativePath)); + FileUrlResource resource = new FileUrlResource(createRelativeURL(relativePath)); + resource.useCaches = this.useCaches; + return resource; } } diff --git a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java index 80ce1680590..8ca9b80c0dc 100644 --- a/spring-core/src/main/java/org/springframework/core/io/UrlResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/UrlResource.java @@ -67,6 +67,12 @@ public class UrlResource extends AbstractFileResolvingResource { @Nullable private volatile String cleanedUrl; + /** + * Whether to use URLConnection caches ({@code null} means default). + */ + @Nullable + volatile Boolean useCaches; + /** * Create a new {@code UrlResource} based on the given URL object. @@ -216,11 +222,22 @@ public class UrlResource extends AbstractFileResolvingResource { return cleanedUrl; } + /** + * Set an explicit flag for {@link URLConnection#setUseCaches}, + * to be applied for any {@link URLConnection} operation in this resource. + *
By default, caching will be applied only to jar resources. + * An explicit {@code true} flag applies caching to all resources, whereas an + * explicit {@code false} flag turns off caching for jar resources as well. + * @since 6.2.10 + * @see ResourceUtils#useCachesIfNecessary + */ + public void setUseCaches(boolean useCaches) { + this.useCaches = useCaches; + } + /** * This implementation opens an InputStream for the given URL. - *
It sets the {@code useCaches} flag to {@code false},
- * mainly to avoid jar file locking on Windows.
* @see java.net.URL#openConnection()
* @see java.net.URLConnection#setUseCaches(boolean)
* @see java.net.URLConnection#getInputStream()
@@ -251,6 +268,17 @@ public class UrlResource extends AbstractFileResolvingResource {
}
}
+ @Override
+ void useCachesIfNecessary(URLConnection con) {
+ Boolean useCaches = this.useCaches;
+ if (useCaches != null) {
+ con.setUseCaches(useCaches);
+ }
+ else {
+ super.useCachesIfNecessary(con);
+ }
+ }
+
/**
* This implementation returns the underlying URL reference.
*/
@@ -305,7 +333,9 @@ public class UrlResource extends AbstractFileResolvingResource {
*/
@Override
public Resource createRelative(String relativePath) throws MalformedURLException {
- return new UrlResource(createRelativeURL(relativePath));
+ UrlResource resource = new UrlResource(createRelativeURL(relativePath));
+ resource.useCaches = this.useCaches;
+ return resource;
}
/**
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 1634796d157..0ecabb7e19d 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
@@ -260,7 +260,8 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
private PathMatcher pathMatcher = new AntPathMatcher();
- private boolean useCaches = true;
+ @Nullable
+ private Boolean useCaches;
private final Map Note that {@link JarURLConnection#setDefaultUseCaches} can be turned off
* independently. This resolver-level setting is designed to only enforce
- * {@code JarURLConnection#setUseCaches(false)} if necessary but otherwise
- * leaves the JVM-level default in place.
+ * {@code JarURLConnection#setUseCaches(true/false)} if necessary but otherwise
+ * leaves the JVM-level default in place (if this setter has not been called).
+ * As of 6.2.10, this setting propagates to {@link UrlResource#setUseCaches}.
* @since 6.1.19
* @see JarURLConnection#setUseCaches
+ * @see UrlResource#setUseCaches
* @see #clearCache()
*/
public void setUseCaches(boolean useCaches) {
@@ -355,7 +358,11 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
@Override
public Resource getResource(String location) {
- return getResourceLoader().getResource(location);
+ Resource resource = getResourceLoader().getResource(location);
+ if (this.useCaches != null && resource instanceof UrlResource urlResource) {
+ urlResource.setUseCaches(this.useCaches);
+ }
+ return resource;
}
@Override
@@ -473,20 +480,27 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
}
}
else {
+ UrlResource resource = null;
String urlString = url.toString();
String cleanedPath = StringUtils.cleanPath(urlString);
if (!cleanedPath.equals(urlString)) {
// Prefer cleaned URL, aligned with UrlResource#createRelative(String)
try {
// Retain original URL instance, potentially including custom URLStreamHandler.
- return new UrlResource(new URL(url, cleanedPath));
+ resource = new UrlResource(new URL(url, cleanedPath));
}
catch (MalformedURLException ex) {
// Fallback to regular URL construction below...
}
}
// Retain original URL instance, potentially including custom URLStreamHandler.
- return new UrlResource(url);
+ if (resource == null) {
+ resource = new UrlResource(url);
+ }
+ if (this.useCaches != null) {
+ resource.setUseCaches(this.useCaches);
+ }
+ return resource;
}
}
@@ -505,6 +519,9 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
UrlResource jarResource = (ResourceUtils.URL_PROTOCOL_JAR.equals(url.getProtocol()) ?
new UrlResource(url) :
new UrlResource(ResourceUtils.JAR_URL_PREFIX + url + ResourceUtils.JAR_URL_SEPARATOR));
+ if (this.useCaches != null) {
+ jarResource.setUseCaches(this.useCaches);
+ }
if (jarResource.exists()) {
result.add(jarResource);
}
@@ -556,7 +573,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
Set