Avoid calling URL.getContent() when defining a package

URL.getContent() is shorthand for URL.openConnection().getContent().
It creates an InputStream that isn't explicitly closed. This means
that a file handle remains open until the URLConnection is garbage
collected. This can lead to the process exceeding the limit for open
files.

Previously, LaunchedURLClassLoader was using getConent() when
proactively defining a package for a class that is about to be loaded.
getContent() was used to access nested jar files to check if they
contained the package and, if so, to retrieve the jar's manifest.

In place of using getContent(), this commit uses JarURLConnection's
getJarFile() method which provides access to the JarFile without the
unwanted side-effect of opening an input stream.

Closes gh-7180
This commit is contained in:
Andy Wilkinson 2016-10-18 13:35:33 +01:00
parent 24f8c737fb
commit a31180dd68

View File

@ -24,9 +24,9 @@ import java.net.URLConnection;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.Enumeration;
import java.util.jar.JarFile;
import org.springframework.boot.loader.jar.Handler;
import org.springframework.boot.loader.jar.JarFile;
/**
* {@link ClassLoader} used by the {@link Launcher}.
@ -131,8 +131,10 @@ public class LaunchedURLClassLoader extends URLClassLoader {
String classEntryName = className.replace(".", "/") + ".class";
for (URL url : getURLs()) {
try {
if (url.getContent() instanceof JarFile) {
JarFile jarFile = (JarFile) url.getContent();
URLConnection connection = url.openConnection();
if (connection instanceof JarURLConnection) {
JarFile jarFile = ((JarURLConnection) connection)
.getJarFile();
if (jarFile.getEntry(classEntryName) != null
&& jarFile.getEntry(packageEntryName) != null
&& jarFile.getManifest() != null) {
@ -175,8 +177,8 @@ public class LaunchedURLClassLoader extends URLClassLoader {
private void clearCache(URLConnection connection) throws IOException {
Object jarFile = ((JarURLConnection) connection).getJarFile();
if (jarFile instanceof JarFile) {
((JarFile) jarFile).clearCache();
if (jarFile instanceof org.springframework.boot.loader.jar.JarFile) {
((org.springframework.boot.loader.jar.JarFile) jarFile).clearCache();
}
}