ClassPreloadService

Preloading classes at startup

A ClassCircularityError is an indication of either conflicting packaging, or this known JVM bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4699981, which Sun has promised to fix for j2se6 (Mustang) http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4670071.

 

A workaround is to prefetch classes on startup to avoid conflicts due to attempts to load the same classes in multiple threads. The following org.jboss.mx.loading.ClassPreloadService was added to 4.0.3SP1, and can be added to either the conf/jboss-service.xml to preload all jboss classes, or a deployment to load its classes. The mbean fragment in the javadoc illustrates how the server can be deployed.

 

/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.mx.loading;

import java.net.URL;
import java.io.InputStream;
import java.io.IOException;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipEntry;

import org.jboss.logging.Logger;

/**
 A simple service that can be used preload all classes in the classpath
 of the thread context class loader seen in the start method as the thread
 context class loader. A simple xmbean fragment for deploying the service
 is:
 
    <mbean code="org.jboss.mx.loading.ClassPreloadService"
      name="jboss.mx:service=ClassPreloadService"
      xmbean-dd="">
      <xmbean>
         <operation>
            <name>start</name>
         </operation>
      </xmbean>
   </mbean>

 @author Scott.Stark@jboss.org
 @version $Revision: 1.1 $
 */
public class ClassPreloadService
{
   /**
    Load all classes seen the TCL classpath. This entails a scan of every
    archive in the TCL classpath URLs for .class entries.
    */
   public void start()
   {
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      URL[] cp = ClassLoaderUtils.getClassLoaderURLs(loader);
      Logger log = Logger.getLogger(ClassPreloadService.class);
      boolean trace = log.isTraceEnabled();
      int loadedClasses = 0;
      int loadErrors = 0;
      for(int n = 0; n < cp.length; n ++)
      {
         URL u = cp[n];
         try
         {
            InputStream is = u.openStream();
            ZipInputStream zis = new ZipInputStream(is);
            ZipEntry ze = zis.getNextEntry();
            while (ze != null)
            {
               String name = ze.getName();
               if (name.endsWith(".class"))
               {
                  int length = name.length();
                  String cname = name.replace('/', '.').substring(0, length - 6);
                  try
                  {
                     Class c = loader.loadClass(cname);
                     loadedClasses ++;
                     if (trace)
                        log.trace("loaded class: " + cname);
                  }
                  catch (Throwable e)
                  {
                     loadErrors ++;
                     if( trace )
                        log.trace("Failed to load class, "+e.getMessage());
                  }
               }
               ze = zis.getNextEntry();
            }
            zis.close();
         }
         catch (IOException ignore)
         {
            // Not a jar
         }
      }
      log.info("Loaded "+loadedClasses+" classes, "+loadErrors+" CNFEs");
   }
}

 

4.0.4+ Updates

As of the 4.0.4 release, the ClassPreloadService has been expanded to support includes/excludes attributes that allow more control over which classes in its classpath are loaded. The new sample mbean/xmbean descriptor is:

    <mbean code="org.jboss.mx.loading.ClassPreloadService"
      name="jboss.mx:service=ClassPreloadService"
      xmbean-dd="">
      <xmbean>
          <attribute access="read-write"
             getMethod="getIncludePatterns" setMethod="setIncludePatterns">
             <description>The patterns for classpath includes</description>
             <name>IncludePatterns</name>
             <type>[Ljava.lang.String;</type>
          </attribute>
          <attribute access="read-write"
             getMethod="getExcludePatterns" setMethod="setExcludePatterns">
             <description>The patterns for classpath excludes</description>
             <name>ExcludePatterns</name>
             <type>[Ljava.lang.String;</type>
          </attribute>
          <attribute access="read-write"
             getMethod="isSimpleMatch" setMethod="setSimpleMatch">
             <description>A flag indicate if String.endsWith matching of includes/excludes should be used</description>
             <name>SimpleMatch</name>
             <type>boolean</type>
          </attribute>
         <operation>
            <name>start</name>
         </operation>
      </xmbean>
       <attribute name="ExcludePatterns">jbossmq.jar</attribute>
       <attribute name="IncludePatterns"></attribute>
       <attribute name="SimpleMatch">true</attribute>
   </mbean>

 

  • ExcludePatterns : The RE expressions for classpath elements to excludes. Excludes take precedence over includes.

  • IncludePatterns : The RE expressions for classpath elements to include. If empty all non-excluded elements are added.

  • SimpleMatch : A flag indicate if String.endsWith matching of includes/excludes should be used.