org.springframework.boot.loader.LaunchedURLClassLoader Maven / Gradle / Ivy
/*
* Copyright 2012-2017 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.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
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.lang.UsesJava7;
/**
* {@link ClassLoader} used by the {@link Launcher}.
*
* @author Phillip Webb
* @author Dave Syer
* @author Andy Wilkinson
*/
public class LaunchedURLClassLoader extends URLClassLoader {
static {
performParallelCapableRegistration();
}
/**
* Create a new {@link LaunchedURLClassLoader} instance.
* @param urls the URLs from which to load classes and resources
* @param parent the parent class loader for delegation
*/
public LaunchedURLClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
@Override
public URL findResource(String name) {
Handler.setUseFastConnectionExceptions(true);
try {
return super.findResource(name);
}
finally {
Handler.setUseFastConnectionExceptions(false);
}
}
@Override
public Enumeration findResources(String name) throws IOException {
Handler.setUseFastConnectionExceptions(true);
try {
return super.findResources(name);
}
finally {
Handler.setUseFastConnectionExceptions(false);
}
}
@Override
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
Handler.setUseFastConnectionExceptions(true);
try {
try {
definePackageIfNecessary(name);
}
catch (IllegalArgumentException ex) {
// Tolerate race condition due to being parallel capable
if (getPackage(name) == null) {
// This should never happen as the IllegalArgumentException indicates
// that the package has already been defined and, therefore,
// getPackage(name) should not return null.
throw new AssertionError("Package " + name + " has already been "
+ "defined but it could not be found");
}
}
return super.loadClass(name, resolve);
}
finally {
Handler.setUseFastConnectionExceptions(false);
}
}
/**
* Define a package before a {@code findClass} call is made. This is necessary to
* ensure that the appropriate manifest for nested JARs is associated with the
* package.
* @param className the class name being found
*/
private void definePackageIfNecessary(String className) {
int lastDot = className.lastIndexOf('.');
if (lastDot >= 0) {
String packageName = className.substring(0, lastDot);
if (getPackage(packageName) == null) {
try {
definePackage(className, packageName);
}
catch (IllegalArgumentException ex) {
// Tolerate race condition due to being parallel capable
if (getPackage(packageName) == null) {
// This should never happen as the IllegalArgumentException
// indicates that the package has already been defined and,
// therefore, getPackage(name) should not have returned null.
throw new AssertionError(
"Package " + packageName + " has already been defined "
+ "but it could not be found");
}
}
}
}
}
private void definePackage(final String className, final String packageName) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction