diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java index 8e2cebef36..cdaabe15a1 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java @@ -36,8 +36,19 @@ import org.springframework.boot.loader.jar.JarFile; */ public class LaunchedURLClassLoader extends URLClassLoader { + static { + try { + ClassLoader.registerAsParallelCapable(); + } + catch (NoSuchMethodError ex) { + // Not available on earlier JDKs + } + } + private final ClassLoader rootClassLoader; + private final LockProvider lockProvider; + /** * Create a new {@link LaunchedURLClassLoader} instance. * @param urls the URLs from which to load classes and resources @@ -46,6 +57,17 @@ public class LaunchedURLClassLoader extends URLClassLoader { public LaunchedURLClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); this.rootClassLoader = findRootClassLoader(parent); + this.lockProvider = createLockProvider(); + } + + private LockProvider createLockProvider() { + try { + ClassLoader.class.getMethod("getClassLoadingLock", String.class); + return new Java7LockProvider(); + } + catch (NoSuchMethodException ex) { + return new LockProvider(); + } } private ClassLoader findRootClassLoader(ClassLoader classLoader) { @@ -126,7 +148,7 @@ public class LaunchedURLClassLoader extends URLClassLoader { @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - synchronized (this) { + synchronized (this.lockProvider.getLock(this, name)) { Class loadedClass = findLoadedClass(name); if (loadedClass == null) { Handler.setUseFastConnectionExceptions(true); @@ -222,4 +244,27 @@ public class LaunchedURLClassLoader extends URLClassLoader { } } + /** + * Strategy used to provide the synchronize lock object to use when loading classes. + */ + private static class LockProvider { + + public Object getLock(LaunchedURLClassLoader classLoader, String className) { + return classLoader; + } + + } + + /** + * Java 7 specific {@link LockProvider}. + */ + private static class Java7LockProvider extends LockProvider { + + @Override + public Object getLock(LaunchedURLClassLoader classLoader, String className) { + return classLoader.getClassLoadingLock(className); + } + + } + }