Commit 951d0b0f authored by Phillip Webb's avatar Phillip Webb

Fix exploded jar classloader issues

Fix a bug in `ExplodedURLClassLoader` and merge the code into the
existing `LaunchedURLClassLoader` class. Also polish a few method
names relating to layer support.

See gh-19848
See gh-19767
parent b4229239
...@@ -164,8 +164,8 @@ public abstract class ExecutableArchiveLauncher extends Launcher { ...@@ -164,8 +164,8 @@ public abstract class ExecutableArchiveLauncher extends Launcher {
} }
@Override @Override
protected boolean supportsNestedJars() { protected boolean isExploded() {
return this.archive.supportsNestedJars(); return this.archive.isExploded();
} }
/** /**
......
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.loader;
import java.net.URL;
import java.net.URLClassLoader;
/**
* {@link URLClassLoader} used for exploded archives.
*
* @author Phillip Webb
*/
class ExplodedURLClassLoader extends URLClassLoader {
ExplodedURLClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
try {
Class<?> result = findClass(name);
if (resolve) {
resolveClass(result);
}
return result;
}
catch (ClassNotFoundException ex) {
}
return super.loadClass(name, resolve);
}
}
...@@ -42,17 +42,33 @@ public class LaunchedURLClassLoader extends URLClassLoader { ...@@ -42,17 +42,33 @@ public class LaunchedURLClassLoader extends URLClassLoader {
ClassLoader.registerAsParallelCapable(); ClassLoader.registerAsParallelCapable();
} }
private final boolean exploded;
/** /**
* Create a new {@link LaunchedURLClassLoader} instance. * Create a new {@link LaunchedURLClassLoader} instance.
* @param urls the URLs from which to load classes and resources * @param urls the URLs from which to load classes and resources
* @param parent the parent class loader for delegation * @param parent the parent class loader for delegation
*/ */
public LaunchedURLClassLoader(URL[] urls, ClassLoader parent) { public LaunchedURLClassLoader(URL[] urls, ClassLoader parent) {
this(false, urls, parent);
}
/**
* Create a new {@link LaunchedURLClassLoader} instance.
* @param exploded the the underlying archive is exploded
* @param urls the URLs from which to load classes and resources
* @param parent the parent class loader for delegation
*/
public LaunchedURLClassLoader(boolean exploded, URL[] urls, ClassLoader parent) {
super(urls, parent); super(urls, parent);
this.exploded = exploded;
} }
@Override @Override
public URL findResource(String name) { public URL findResource(String name) {
if (this.exploded) {
return super.findResource(name);
}
Handler.setUseFastConnectionExceptions(true); Handler.setUseFastConnectionExceptions(true);
try { try {
return super.findResource(name); return super.findResource(name);
...@@ -64,6 +80,9 @@ public class LaunchedURLClassLoader extends URLClassLoader { ...@@ -64,6 +80,9 @@ public class LaunchedURLClassLoader extends URLClassLoader {
@Override @Override
public Enumeration<URL> findResources(String name) throws IOException { public Enumeration<URL> findResources(String name) throws IOException {
if (this.exploded) {
return super.findResources(name);
}
Handler.setUseFastConnectionExceptions(true); Handler.setUseFastConnectionExceptions(true);
try { try {
return new UseFastConnectionExceptionsEnumeration(super.findResources(name)); return new UseFastConnectionExceptionsEnumeration(super.findResources(name));
...@@ -86,6 +105,9 @@ public class LaunchedURLClassLoader extends URLClassLoader { ...@@ -86,6 +105,9 @@ public class LaunchedURLClassLoader extends URLClassLoader {
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
} }
} }
if (this.exploded) {
return super.loadClass(name, resolve);
}
Handler.setUseFastConnectionExceptions(true); Handler.setUseFastConnectionExceptions(true);
try { try {
try { try {
...@@ -168,6 +190,9 @@ public class LaunchedURLClassLoader extends URLClassLoader { ...@@ -168,6 +190,9 @@ public class LaunchedURLClassLoader extends URLClassLoader {
* Clear URL caches. * Clear URL caches.
*/ */
public void clearCache() { public void clearCache() {
if (this.exploded) {
return;
}
for (URL url : getURLs()) { for (URL url : getURLs()) {
try { try {
URLConnection connection = url.openConnection(); URLConnection connection = url.openConnection();
......
...@@ -49,7 +49,7 @@ public abstract class Launcher { ...@@ -49,7 +49,7 @@ public abstract class Launcher {
* @throws Exception if the application fails to launch * @throws Exception if the application fails to launch
*/ */
protected void launch(String[] args) throws Exception { protected void launch(String[] args) throws Exception {
if (supportsNestedJars()) { if (!isExploded()) {
JarFile.registerUrlProtocolHandler(); JarFile.registerUrlProtocolHandler();
} }
ClassLoader classLoader = createClassLoader(getClassPathArchivesIterator()); ClassLoader classLoader = createClassLoader(getClassPathArchivesIterator());
...@@ -94,10 +94,7 @@ public abstract class Launcher { ...@@ -94,10 +94,7 @@ public abstract class Launcher {
* @throws Exception if the classloader cannot be created * @throws Exception if the classloader cannot be created
*/ */
protected ClassLoader createClassLoader(URL[] urls) throws Exception { protected ClassLoader createClassLoader(URL[] urls) throws Exception {
if (supportsNestedJars()) { return new LaunchedURLClassLoader(isExploded(), urls, getClass().getClassLoader());
return new LaunchedURLClassLoader(urls, getClass().getClassLoader());
}
return new ExplodedURLClassLoader(urls, getClass().getClassLoader());
} }
/** /**
...@@ -168,12 +165,12 @@ public abstract class Launcher { ...@@ -168,12 +165,12 @@ public abstract class Launcher {
} }
/** /**
* Returns if the launcher needs to support fully nested JARs. If this method returns * Returns if the launcher is running in an exploded mode. If this method returns
* {@code false} then only regular JARs are supported and the additional URL and * {@code true} then only regular JARs are supported and the additional URL and
* ClassLoader support infrastructure will not be installed. * ClassLoader support infrastructure can be optimized.
* @return if nested JARs are supported * @return if the jar is exploded.
*/ */
protected boolean supportsNestedJars() { protected boolean isExploded() {
return true; return true;
} }
......
...@@ -90,8 +90,12 @@ public interface Archive extends Iterable<Archive.Entry>, AutoCloseable { ...@@ -90,8 +90,12 @@ public interface Archive extends Iterable<Archive.Entry>, AutoCloseable {
@Override @Override
Iterator<Entry> iterator(); Iterator<Entry> iterator();
default boolean supportsNestedJars() { /**
return true; * Return if the archive is exploded (already unpacked).
* @return if the archive is exploded
*/
default boolean isExploded() {
return false;
} }
/** /**
......
...@@ -114,8 +114,8 @@ public class ExplodedArchive implements Archive { ...@@ -114,8 +114,8 @@ public class ExplodedArchive implements Archive {
} }
@Override @Override
public boolean supportsNestedJars() { public boolean isExploded() {
return false; return true;
} }
@Override @Override
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment