Skip to content

Commit a8777ed

Browse files
author
Phillip Webb
committed
Add JarFile caching
Cache root jar files in the Handler and also store nested jar files in the JarEntryData. See gh-1119
1 parent 8819529 commit a8777ed

File tree

3 files changed

+46
-7
lines changed

3 files changed

+46
-7
lines changed

spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818

1919
import java.io.File;
2020
import java.io.IOException;
21+
import java.lang.ref.SoftReference;
2122
import java.lang.reflect.Method;
2223
import java.net.MalformedURLException;
2324
import java.net.URL;
2425
import java.net.URLConnection;
2526
import java.net.URLStreamHandler;
27+
import java.util.Map;
28+
import java.util.concurrent.ConcurrentHashMap;
2629
import java.util.logging.Level;
2730
import java.util.logging.Logger;
2831

@@ -55,6 +58,11 @@ public class Handler extends URLStreamHandler {
5558
OPEN_CONNECTION_METHOD = method;
5659
}
5760

61+
private static SoftReference<Map<File, JarFile>> rootFileCache;
62+
static {
63+
rootFileCache = new SoftReference<Map<File, JarFile>>(null);
64+
}
65+
5866
private final Logger logger = Logger.getLogger(getClass().getName());
5967

6068
private final JarFile jarFile;
@@ -153,7 +161,14 @@ private JarFile getRootJarFile(String name) throws IOException {
153161
throw new IllegalStateException("Not a file URL");
154162
}
155163
String path = name.substring(FILE_PROTOCOL.length());
156-
return new JarFile(new File(path));
164+
File file = new File(path);
165+
Map<File, JarFile> cache = rootFileCache.get();
166+
JarFile jarFile = (cache == null ? null : cache.get(file));
167+
if (jarFile == null) {
168+
jarFile = new JarFile(file);
169+
addToRootFileCache(file, jarFile);
170+
}
171+
return jarFile;
157172
}
158173
catch (Exception ex) {
159174
throw new IOException("Unable to open root Jar file '" + name + "'", ex);
@@ -168,4 +183,19 @@ private JarFile getNestedJarFile(JarFile jarFile, String name) throws IOExceptio
168183
}
169184
return jarFile.getNestedJarFile(jarEntry);
170185
}
186+
187+
/**
188+
* Add the given {@link JarFile} to the root file cache.
189+
* @param sourceFile the source file to add
190+
* @param jarFile the jar file.
191+
*/
192+
static void addToRootFileCache(File sourceFile, JarFile jarFile) {
193+
Map<File, JarFile> cache = rootFileCache.get();
194+
if (cache == null) {
195+
cache = new ConcurrentHashMap<File, JarFile>();
196+
rootFileCache = new SoftReference<Map<File, JarFile>>(cache);
197+
}
198+
cache.put(sourceFile, jarFile);
199+
}
200+
171201
}

spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public final class JarEntryData {
5353

5454
private SoftReference<JarEntry> entry;
5555

56+
JarFile nestedJar;
57+
5658
public JarEntryData(JarFile source, byte[] header, InputStream inputStream)
5759
throws IOException {
5860
this.source = source;

spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -322,21 +322,28 @@ public synchronized JarFile getNestedJarFile(final ZipEntry ze) throws IOExcepti
322322
* @return a {@link JarFile} for the entry
323323
* @throws IOException
324324
*/
325-
public synchronized JarFile getNestedJarFile(final JarEntryData sourceEntry)
325+
public synchronized JarFile getNestedJarFile(JarEntryData sourceEntry)
326326
throws IOException {
327327
try {
328-
if (sourceEntry.isDirectory()) {
329-
return getNestedJarFileFromDirectoryEntry(sourceEntry);
328+
if (sourceEntry.nestedJar == null) {
329+
sourceEntry.nestedJar = createJarFileFromEntry(sourceEntry);
330330
}
331-
return getNestedJarFileFromFileEntry(sourceEntry);
331+
return sourceEntry.nestedJar;
332332
}
333333
catch (IOException ex) {
334334
throw new IOException("Unable to open nested jar file '"
335335
+ sourceEntry.getName() + "'", ex);
336336
}
337337
}
338338

339-
private JarFile getNestedJarFileFromDirectoryEntry(JarEntryData sourceEntry)
339+
private JarFile createJarFileFromEntry(JarEntryData sourceEntry) throws IOException {
340+
if (sourceEntry.isDirectory()) {
341+
return createJarFileFromDirectoryEntry(sourceEntry);
342+
}
343+
return createJarFileFromFileEntry(sourceEntry);
344+
}
345+
346+
private JarFile createJarFileFromDirectoryEntry(JarEntryData sourceEntry)
340347
throws IOException {
341348
final AsciiBytes sourceName = sourceEntry.getName();
342349
JarEntryFilter filter = new JarEntryFilter() {
@@ -353,7 +360,7 @@ public AsciiBytes apply(AsciiBytes name, JarEntryData entryData) {
353360
this.entries, filter);
354361
}
355362

356-
private JarFile getNestedJarFileFromFileEntry(JarEntryData sourceEntry)
363+
private JarFile createJarFileFromFileEntry(JarEntryData sourceEntry)
357364
throws IOException {
358365
if (sourceEntry.getMethod() != ZipEntry.STORED) {
359366
throw new IllegalStateException("Unable to open nested compressed entry "

0 commit comments

Comments
 (0)