📄 adaptiveclassloader.java
字号:
/* * Copyright (c) 1997-1999 The Java Apache Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Java Apache * Project for use in the Apache JServ servlet engine project * <http://java.apache.org/>." * * 4. The names "Apache JServ", "Apache JServ Servlet Engine" and * "Java Apache Project" must not be used to endorse or promote products * derived from this software without prior written permission. * * 5. Products derived from this software may not be called "Apache JServ" * nor may "Apache" nor "Apache JServ" appear in their names without * prior written permission of the Java Apache Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Java Apache * Project for use in the Apache JServ servlet engine project * <http://java.apache.org/>." * * THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JAVA APACHE PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * This software consists of voluntary contributions made by many * individuals on behalf of the Java Apache Group. For more information * on the Java Apache Project and the Apache JServ Servlet Engine project, * please see <http://java.apache.org/>. * */package org.apache.tomcat.loader;//package org.apache.java.lang;import java.io.*;import java.lang.*;import java.net.*;import java.text.*;import java.util.*;import java.util.zip.*;import java.security.*;/** * A class loader that loads classes from directories and/or zip-format * file such as JAR file. It tracks the modification time of the classes * it loads to permit reloading through re-instantiation. * <P> * When the classloader reports its creator that one of the classes it * has loaded has changed on disk, it should discard the classloader * and create a new instance using <CODE>reinstantiate</CODE>. * The classes are then reloaded into the new classloader as required. * * <P>The classloader can also load resources, which are a means * for packaging application data such as images within a jar file * or directory. * * <P>The classloader always first tries to load classes and resources * from the system, and uses it's own path if that fails. This is also * done if an empty repository is passed at construction. * * <P><B>How autoreload works:</B></P> * * <P>The Java VM considers two classes the same if they have the same * fully-qualified name <B>and</B> if they were loaded from the same * <CODE>ClassLoader</CODE>. * * <P>There is no way for a classloader to 'undefine' a class once it * has been loaded. However, the servlet engine can discard a * classloader and the classes it contains, causing the * * <P>The <CODE>JServServletManager</CODE> creates a new instance of * the classloader each time it detects that any of the loaded classes * have changed. * * <P>Before terminating, all servlets are destroyed. * * <P>According to the Java Language Specification (JLS), classes may * be garbage-collected when there are no longer any instances of that * class and the <CODE>java.lang.Class</CODE> object is finalizable. * It is intended that this be the case when a <CODE>JServClassLoader</CODE> * is discarded. * * <P>Many VM releases did not implement class garbage collection * properly. In such a VM, the memory usage will continue to grow if * autoreloading is enable. Running the VM with * <CODE>-verbosegc</CODE> (or the corresponding option for * non-Javasoft VMs) may give some debugging information. * * <P>It is important that the <CODE>destroy</CODE> method be * implemented properly, as servlets may be destroyed and * reinitialized several times in the life of a VM. * * @author Francis J. Lacoste * @author Martin Pool * @author Jim Heintz * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a> * @version $Revision: 1.9.2.2 $ $Date: 2000/11/16 22:04:42 $ * @see java.lang.ClassLoader */public class AdaptiveClassLoader extends ClassLoader { private static final int debug=0; /** * Instance of the SecurityManager installed. */ static protected SecurityManager sm; /** * Generation counter, incremented for each classloader as they are * created. */ static private int generationCounter = 0; /** * Generation number of the classloader, used to distinguish between * different instances. */ private int generation; /** * Cache of the loaded classes. This contains ClassCacheEntry keyed * by class names. */ protected Hashtable cache; /** * The classpath which this classloader searches for class definitions. * Each element of the vector should be either a directory, a .zip * file, or a .jar file. * <p> * It may be empty when only system classes are controlled. */ protected Vector repository; /** * A parent class loader for delegation of finding a class definition. * JDK 1.2 contains parent class loaders as part of java.lang.ClassLoader, the parent * being passed to a constructor, and retreived with getParent() method. For JDK 1.1 * compatibility, we'll duplicate the 1.2 private member var. */ protected ClassLoader parent; /** * Private class used to maintain information about the classes that * we loaded. */ private static class ClassCacheEntry { /** * The actual loaded class */ Class loadedClass; /** * The file from which this class was loaded; or null if * it was loaded from the system. */ File origin; /** * The time at which the class was loaded from the origin * file, in ms since the epoch. */ long lastModified; /** * Check whether this class was loaded from the system. */ public boolean isSystemClass() { return origin == null; } } //------------------------------------------------------- Constructors /** * Creates a new class loader that will load classes from specified * class repositories, delegating first to the passed parent for definitions. * * @param classRepository An set of File classes indicating * directories and/or zip/jar files. It may be empty when * only system classes are loaded. * @param theParent A containing class loader for initial delegation of class * definition serach. * @throw java.lang.IllegalArgumentException if the objects contained * in the vector are not a file instance or the file is not * a valid directory or a zip/jar file. */ public AdaptiveClassLoader() { // Create the cache of loaded classes cache = new Hashtable(); } public void setRepository( Vector classRepository ) throws IllegalArgumentException { // Verify that all the repository are valid. Enumeration e = classRepository.elements(); while(e.hasMoreElements()) { ClassRepository cp = (ClassRepository) e.nextElement(); File file; String[] files; int i; // Check to see if element is a File instance. try { file = cp.getFile(); } catch (ClassCastException objectIsNotFile) { throw new IllegalArgumentException("Object " + cp + "is not a valid \"File\" instance"); } // org.apache.java.io.XXX files=SimpleFileFilter.fileOrFiles(file); if (files!=null) { for (i=0;i<files.length;i++) { file=new File(files[i]); // Check to see if we have proper access. if (!file.exists()) { throw new IllegalArgumentException("Repository " + file.getAbsolutePath() + " doesn't exist!"); } else if (!file.canRead()) { throw new IllegalArgumentException( "Do not have read access for file " + file.getAbsolutePath()); } // Check that it is a directory or zip/jar file if (!(file.isDirectory() || isZipOrJarArchive(file))) { throw new IllegalArgumentException( file.getAbsolutePath() + " is not a directory or zip/jar file" + " or if it's a zip/jar file then it is corrupted."); } } } } // Store the class repository for use this.repository = classRepository; // Increment and store generation counter this.generation = generationCounter++; } public void setParent( ClassLoader p ) { parent=p; } void log( String s ) { System.out.println("AdaptiveClassLoader: " + s ); } //------------------------------------------------------- Methods /** * Test if a file is a ZIP or JAR archive. * * @param file the file to be tested. * @return true if the file is a ZIP/JAR archive, false otherwise. */ private boolean isZipOrJarArchive(File file) { boolean isArchive = true; ZipFile zipFile = null; try { zipFile = new ZipFile(file); } catch (ZipException zipCurrupted) { isArchive = false; } catch (IOException anyIOError) { isArchive = false; } finally { if (zipFile != null) { try { zipFile.close(); } catch (IOException ignored) {} } } return isArchive; } /** * Check to see if a given class should be reloaded because of a * modification to the original class. * * @param className The name of the class to check for modification. */ public synchronized boolean shouldReload(String classname) { return checkExpired( classname ); } protected boolean checkExpired(String classname ) { ClassCacheEntry entry = (ClassCacheEntry) cache.get(classname); if (entry == null) { // class wasn't even loaded return false; } else if (entry.isSystemClass()) { // System classes cannot be reloaded return false; } else { return (entry.origin.lastModified() != entry.lastModified); } } /** * Check whether the classloader should be reinstantiated. * <P> * The classloader must be replaced if there is any class whose * origin file has changed since it was last loaded. */ public synchronized boolean shouldReload() { // Check whether any class has changed Enumeration e = cache.elements(); while (e.hasMoreElements()) { ClassCacheEntry entry = (ClassCacheEntry) e.nextElement(); if( entry.loadedClass==null ) continue; if( debug>5 ) log( "cache entry: " + entry.loadedClass.getName()); if (entry.isSystemClass()) continue; // XXX: Because we want the classloader to be an accurate // reflection of the contents of the repository, we also // reload if a class origin file is now missing. This // probably makes things a bit more fragile, but is OK in // a servlet development situation. <mbp@pharos.com.au> long msOrigin = entry.origin.lastModified(); if (msOrigin == 0) { // class no longer exists return true; } if (msOrigin != entry.lastModified) { // class is modified return true; } } // No changes, no need to reload return false; } /** * Re-instantiate this class loader. * <p> * This method creates a new instance * of the class loader that will load classes form the same path * as this one. */ public AdaptiveClassLoader reinstantiate() { AdaptiveClassLoader cl=new AdaptiveClassLoader(); cl.setParent(parent); cl.setRepository(repository); return cl; } //------------------------------------ Implementation of Classloader /* * XXX: The javadoc for java.lang.ClassLoader says that the * ClassLoader should cache classes so that it can handle repeated * requests for the same class. On the other hand, the JLS seems * to imply that each classloader is only asked to load each class * once. Is this a contradiction? * * Perhaps the second call only applies to classes which have been * garbage-collected? */ /** * Resolves the specified name to a Class. The method loadClass() * is called by the virtual machine. As an abstract method, * loadClass() must be defined in a subclass of ClassLoader. * * @param name the name of the desired Class. * @param resolve true if the Class needs to be resolved; * false if the virtual machine just wants to determine * whether the class exists or not * @return the resulting Class. * @exception ClassNotFoundException if the class loader cannot * find a the requested class. */ protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { if( debug>0) log( "loadClass() " + name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -