Changeset 1959


Ignore:
Timestamp:
2011-12-22 14:42:36 (5 months ago)
Author:
bruno
Message:

Introduce a ClassLoader? cache (to be enabled explicitly using a system property) which is useful when you restart the same Kauri instance frequently in the same JVM (we do this in Lily's test framework).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/core/kauri-runtime/src/main/java/org/kauriproject/runtime/classloading/ClassLoaderBuilder.java

    r967 r1959  
    1616package org.kauriproject.runtime.classloading; 
    1717 
     18import org.apache.commons.logging.Log; 
     19import org.apache.commons.logging.LogFactory; 
    1820import org.kauriproject.runtime.repository.ArtifactRepository; 
    1921import org.kauriproject.runtime.repository.ArtifactNotFoundException; 
    2022 
     23import java.util.HashMap; 
    2124import java.util.List; 
    2225import java.util.ArrayList; 
     
    2528import java.net.MalformedURLException; 
    2629import java.io.File; 
     30import java.util.Map; 
    2731 
    2832public class ClassLoaderBuilder { 
    29     public static ClassLoader build(List<ClasspathEntry> classpathEntries, ClassLoader parentClassLoader, 
     33    private static Map<String, ClassLoader> classLoaderCache; 
     34    private static boolean classLoaderCacheEnabled = true; 
     35    static { 
     36        classLoaderCacheEnabled = System.getProperty("kauri.cacheclassloaders") != null; 
     37        if (classLoaderCacheEnabled) { 
     38            classLoaderCache = new HashMap<String, ClassLoader>(); 
     39        } 
     40    } 
     41     
     42    public static synchronized ClassLoader build(List<ClasspathEntry> classpathEntries, ClassLoader parentClassLoader, 
     43            ArtifactRepository repository) throws ArtifactNotFoundException, MalformedURLException { 
     44         
     45        if (classLoaderCacheEnabled) { 
     46            // 
     47            // About the ClassLoader cache: 
     48            //  The ClassLoader cache was introduced to handle leaks in the 'Perm Gen' and 'Code Cache' 
     49            //  JVM memory spaces when repeatedly restarting Kauri within the same JVM. In such cases, 
     50            //  on each restart Kauri would construct new class loaders, hence the classes loaded through 
     51            //  them would be new and would stress those JVM memory spaces. 
     52            // 
     53            //  The solution here is good enough for what it is intended to do (restarting the same Kauri 
     54            //  app, unchanged, many times). There is no cache cleaning and the cache key calculation 
     55            //  is not perfect, so if you would enable the cache when starting a wide variety of Kauri 
     56            //  apps within one VM or for reloading changed Kauri apps, it could be problematic. 
     57            // 
     58            StringBuilder cacheKeyBuilder = new StringBuilder(2000); 
     59            for (ClasspathEntry entry : classpathEntries) { 
     60                cacheKeyBuilder.append(entry.getArtifactRef()).append("\u2603" /* unicode snowman as separator */); 
     61            } 
     62             
     63            // Add some identification of the parent class loader 
     64            if (parentClassLoader instanceof URLClassLoader) { 
     65                for (URL url : ((URLClassLoader)parentClassLoader).getURLs()) { 
     66                    cacheKeyBuilder.append(url.toString()); 
     67                } 
     68            } 
     69             
     70            String cacheKey = cacheKeyBuilder.toString(); 
     71             
     72            ClassLoader classLoader = classLoaderCache.get(cacheKey); 
     73            if (classLoader == null) { 
     74                Log log = LogFactory.getLog(ClassLoaderBuilder.class); 
     75                log.debug("Creating and caching a new classloader"); 
     76                classLoader = create(classpathEntries, parentClassLoader, repository); 
     77                classLoaderCache.put(cacheKey, classLoader); 
     78            } else if (classLoader.getParent() != parentClassLoader) { 
     79                Log log = LogFactory.getLog(ClassLoaderBuilder.class); 
     80                log.error("Kauri ClassLoader cache: parentClassLoader of cache ClassLoader is different" + 
     81                        " from the specified one. Returning the cached one anyway."); 
     82            } 
     83             
     84            return classLoader;             
     85        } else {         
     86            return create(classpathEntries, parentClassLoader, repository); 
     87        } 
     88    } 
     89     
     90    private static ClassLoader create(List<ClasspathEntry> classpathEntries, ClassLoader parentClassLoader, 
    3091            ArtifactRepository repository) throws ArtifactNotFoundException, MalformedURLException { 
    3192        List<URL> classpath = new ArrayList<URL>(); 
     
    3697        } 
    3798 
    38         return new URLClassLoader(classpath.toArray(new URL[classpath.size()]), parentClassLoader); 
     99        return new URLClassLoader(classpath.toArray(new URL[classpath.size()]), parentClassLoader);         
    39100    } 
    40101} 
Note: See TracChangeset for help on using the changeset viewer.