Callback added to preloader

This commit is contained in:
Andrey Breslav
2013-04-23 14:21:51 +04:00
parent 85bc429efe
commit 7841961989
2 changed files with 44 additions and 10 deletions
@@ -29,6 +29,10 @@ import java.util.zip.ZipInputStream;
public class ClassPreloadingUtils {
public interface ClassHandler {
void beforeDefineClass(String name, int sizeInBytes);
}
/**
* Creates a class loader that loads all classes from {@code jarFiles} into memory to make loading faster (avoid skipping through zip archives).
*
@@ -37,18 +41,28 @@ public class ClassPreloadingUtils {
* @param jarFiles jars to load all classes from
* @param classCountEstimation an estimated number of classes in a the jars
* @param parent (nullable) parent class loader
* @param handler handler to be notified on class definitions done by this class loader, or null
* @return a class loader that reads classes from memory
* @throws IOException on from reading the jar
*/
public static ClassLoader preloadClasses(Collection<File> jarFiles, int classCountEstimation, ClassLoader parent) throws IOException {
public static ClassLoader preloadClasses(
Collection<File> jarFiles, int classCountEstimation, ClassLoader parent, ClassHandler handler
) throws IOException {
Map<String, ResourceData> entries = loadAllClassesFromJars(jarFiles, classCountEstimation);
return createMemoryBasedClassLoader(parent, entries);
return createMemoryBasedClassLoader(parent, entries, handler);
}
public static ClassLoader preloadClasses(
Collection<File> jarFiles, int classCountEstimation, ClassLoader parent
) throws IOException {
return preloadClasses(jarFiles, classCountEstimation, parent, null);
}
private static ClassLoader createMemoryBasedClassLoader(
final ClassLoader parent,
final Map<String, ResourceData> preloadedResources
final Map<String, ResourceData> preloadedResources,
final ClassHandler handler
) {
return new ClassLoader(null) {
@Override
@@ -67,7 +81,12 @@ public class ClassPreloadingUtils {
ResourceData resourceData = preloadedResources.get(internalName);
if (resourceData == null) return null;
return defineClass(name, resourceData.bytes, 0, resourceData.bytes.length);
int sizeInBytes = resourceData.bytes.length;
if (handler != null) {
handler.beforeDefineClass(name, sizeInBytes);
}
return defineClass(name, resourceData.bytes, 0, sizeInBytes);
}
@Override
@@ -44,16 +44,31 @@ public class Preloader {
ClassLoader parent = Preloader.class.getClassLoader();
ClassLoader preloaded = ClassPreloadingUtils.preloadClasses(files, classNumber, parent);
final int[] counter = new int[1];
final int[] size = new int[1];
ClassLoader preloaded = ClassPreloadingUtils.preloadClasses(files, classNumber, parent,
!printTime ? null :
new ClassPreloadingUtils.ClassHandler() {
@Override
public void beforeDefineClass(String name, int sizeInBytes) {
counter[0]++;
size[0] += sizeInBytes;
}
});
Class<?> mainClass = preloaded.loadClass(mainClassCanonicalName);
Method mainMethod = mainClass.getMethod("main", String[].class);
mainMethod.invoke(0, new Object[] {Arrays.copyOfRange(args, PRELOADER_ARG_COUNT, args.length)});
if (printTime) {
long dt = System.nanoTime() - startTime;
System.out.format("Total time: %.3fs\n", dt / 1e9);
try {
mainMethod.invoke(0, new Object[] {Arrays.copyOfRange(args, PRELOADER_ARG_COUNT, args.length)});
}
finally {
if (printTime) {
long dt = System.nanoTime() - startTime;
System.out.format("Total time: %.3fs\n", dt / 1e9);
System.out.println("Loaded classes: " + counter[0]);
System.out.println("Loaded classes size: " + size[0]);
}
}
}