Aligns the classloader creation strategy of the aggregated module with the regular modules

- application classpath URLs are added to the launched aggregated module as well
This commit is contained in:
Marius Bogoevici
2015-09-02 22:49:20 -04:00
parent b9af844ce0
commit 0fd1e37a8f
3 changed files with 29 additions and 27 deletions

View File

@@ -23,6 +23,7 @@ import java.util.List;
import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.util.AsciiBytes;
import org.springframework.cloud.stream.module.utils.ClassloaderUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -80,20 +81,7 @@ public class ModuleJarLauncher extends ExecutableArchiveLauncher {
@Override
protected ClassLoader createClassLoader(URL[] urls) throws Exception {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
if (systemClassLoader instanceof URLClassLoader) {
// add the URLs of the application classloader to the created classloader
// to compensate for LaunchedURLClassLoader not delegating to parent to retrieve resources
@SuppressWarnings("resource")
URLClassLoader systemUrlClassLoader = (URLClassLoader) systemClassLoader;
URL[] mergedUrls = new URL[urls.length + systemUrlClassLoader.getURLs().length];
System.arraycopy(urls, 0, mergedUrls, 0, urls.length);
System.arraycopy(systemUrlClassLoader.getURLs(), 0, mergedUrls, urls.length,
systemUrlClassLoader.getURLs().length);
// add the extension classloader as parent to the created context, if accessible
return new LaunchedURLClassLoader(mergedUrls, systemUrlClassLoader.getParent());
}
return new LaunchedURLClassLoader(urls, systemClassLoader);
return ClassloaderUtils.createModuleClassloader(urls);
}
}

View File

@@ -29,7 +29,6 @@ import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.loader.LaunchedURLClassLoader;
import org.springframework.boot.loader.ModuleJarLauncher;
import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.archive.JarFileArchive;
@@ -146,8 +145,8 @@ public class ModuleLauncher {
mainClassNames.add(jarFileArchive.getMainClass());
arguments.add(toArgArray(moduleLaunchRequest.getArguments()));
}
final ClassLoader classLoader = new LaunchedURLClassLoader(jarURLs.toArray(new URL[jarURLs.size()]),
ClassloaderUtils.getExtensionClassloader());
final ClassLoader classLoader = ClassloaderUtils
.createModuleClassloader(jarURLs.toArray(new URL[jarURLs.size()]));
final List<Class<?>> mainClasses = new ArrayList<>();
for (String mainClass : mainClassNames) {
mainClasses.add(ClassUtils.forName(mainClass, classLoader));

View File

@@ -16,24 +16,39 @@
package org.springframework.cloud.stream.module.utils;
import java.net.URL;
import java.net.URLClassLoader;
import org.springframework.boot.loader.LaunchedURLClassLoader;
import org.springframework.util.Assert;
/**
* @author Marius Bogoevici
*/
public class ClassloaderUtils {
/**
* Retrieves the extension classloader of the current JVM, if accessible. In general the extension classloader is
* found in a hierarchy as the parent of the application classloader. If such a hierarchy does not exist, it will
* return the application classloader itself.
* Creates a ClassLoader for the launched modules by merging the URLs supplied as argument with the URLs that
* make up the additional classpath of the launched JVM (retrieved from the application classloader), and
* setting the extension classloader of the JVM as parent, if accessible.
*
* @return the classloader
* @param urls a list of library URLs
* @return the resulting classloader
*/
public static ClassLoader getExtensionClassloader() {
public static ClassLoader createModuleClassloader(URL[] urls) {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
// try to retrieve the extension classloader
ClassLoader extensionClassLoader = systemClassLoader != null ? systemClassLoader.getParent() : null;
// set the classloader for the module as the extension classloader if available
// fall back to the system classloader (which can also be null) if not available
return extensionClassLoader != null ? extensionClassLoader : systemClassLoader;
if (systemClassLoader instanceof URLClassLoader) {
// add the URLs of the application classloader to the created classloader
// to compensate for LaunchedURLClassLoader not delegating to parent to retrieve resources
@SuppressWarnings("resource")
URLClassLoader systemUrlClassLoader = (URLClassLoader) systemClassLoader;
URL[] mergedUrls = new URL[urls.length + systemUrlClassLoader.getURLs().length];
System.arraycopy(urls, 0, mergedUrls, 0, urls.length);
System.arraycopy(systemUrlClassLoader.getURLs(), 0, mergedUrls, urls.length,
systemUrlClassLoader.getURLs().length);
// add the extension classloader as parent to the created context, if accessible
return new LaunchedURLClassLoader(mergedUrls, systemUrlClassLoader.getParent());
}
return new LaunchedURLClassLoader(urls, systemClassLoader);
}
}