2204 lines · 82.1 KB · Java
RawDownload
/* * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package java.lang; import java.io.InputStream;import java.io.IOException;import java.io.File;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.net.MalformedURLException;import java.net.URL;import java.security.AccessController;import java.security.AccessControlContext;import java.security.CodeSource;import java.security.Policy;import java.security.PrivilegedAction;import java.security.PrivilegedActionException;import java.security.PrivilegedExceptionAction;import java.security.ProtectionDomain;import java.security.cert.Certificate;import java.util.Collections;import java.util.Enumeration;import java.util.HashMap;import java.util.HashSet;import java.util.Set;import java.util.Stack;import java.util.Map;import java.util.Vector;import java.util.Hashtable;import java.util.WeakHashMap;import java.util.concurrent.ConcurrentHashMap;import sun.misc.ClassFileTransformer;import sun.misc.CompoundEnumeration;import sun.misc.Resource;import sun.misc.URLClassPath;import sun.misc.VM;import sun.reflect.Reflection;import sun.security.util.SecurityConstants; /** * A class loader is an object that is responsible for loading classes. The * class <tt>ClassLoader</tt> is an abstract class.  Given the <a * href="#name">binary name</a> of a class, a class loader should attempt to * locate or generate data that constitutes a definition for the class.  A * typical strategy is to transform the name into a file name and then read a * "class file" of that name from a file system. * * <p> Every {@link Class <tt>Class</tt>} object contains a {@link * Class#getClassLoader() reference} to the <tt>ClassLoader</tt> that defined * it. * * <p> <tt>Class</tt> objects for array classes are not created by class * loaders, but are created automatically as required by the Java runtime. * The class loader for an array class, as returned by {@link * Class#getClassLoader()} is the same as the class loader for its element * type; if the element type is a primitive type, then the array class has no * class loader. * * <p> Applications implement subclasses of <tt>ClassLoader</tt> in order to * extend the manner in which the Java virtual machine dynamically loads * classes. * * <p> Class loaders may typically be used by security managers to indicate * security domains. * * <p> The <tt>ClassLoader</tt> class uses a delegation model to search for * classes and resources.  Each instance of <tt>ClassLoader</tt> has an * associated parent class loader.  When requested to find a class or * resource, a <tt>ClassLoader</tt> instance will delegate the search for the * class or resource to its parent class loader before attempting to find the * class or resource itself.  The virtual machine's built-in class loader, * called the "bootstrap class loader", does not itself have a parent but may * serve as the parent of a <tt>ClassLoader</tt> instance. * * <p> Class loaders that support concurrent loading of classes are known as * <em>parallel capable</em> class loaders and are required to register * themselves at their class initialization time by invoking the * {@link * #registerAsParallelCapable <tt>ClassLoader.registerAsParallelCapable</tt>} * method. Note that the <tt>ClassLoader</tt> class is registered as parallel * capable by default. However, its subclasses still need to register themselves * if they are parallel capable. <br> * In environments in which the delegation model is not strictly * hierarchical, class loaders need to be parallel capable, otherwise class * loading can lead to deadlocks because the loader lock is held for the * duration of the class loading process (see {@link #loadClass * <tt>loadClass</tt>} methods). * * <p> Normally, the Java virtual machine loads classes from the local file * system in a platform-dependent manner.  For example, on UNIX systems, the * virtual machine loads classes from the directory defined by the * <tt>CLASSPATH</tt> environment variable. * * <p> However, some classes may not originate from a file; they may originate * from other sources, such as the network, or they could be constructed by an * application.  The method {@link #defineClass(String, byte[], int, int) * <tt>defineClass</tt>} converts an array of bytes into an instance of class * <tt>Class</tt>. Instances of this newly defined class can be created using * {@link Class#newInstance <tt>Class.newInstance</tt>}. * * <p> The methods and constructors of objects created by a class loader may * reference other classes.  To determine the class(es) referred to, the Java * virtual machine invokes the {@link #loadClass <tt>loadClass</tt>} method of * the class loader that originally created the class. * * <p> For example, an application could create a network class loader to * download class files from a server.  Sample code might look like: * * <blockquote><pre> *   ClassLoader loader&nbsp;= new NetworkClassLoader(host,&nbsp;port); *   Object main&nbsp;= loader.loadClass("Main", true).newInstance(); *       &nbsp;.&nbsp;.&nbsp;. * </pre></blockquote> * * <p> The network class loader subclass must define the methods {@link * #findClass <tt>findClass</tt>} and <tt>loadClassData</tt> to load a class * from the network.  Once it has downloaded the bytes that make up the class, * it should use the method {@link #defineClass <tt>defineClass</tt>} to * create a class instance.  A sample implementation is: * * <blockquote><pre> *     class NetworkClassLoader extends ClassLoader { *         String host; *         int port; * *         public Class findClass(String name) { *             byte[] b = loadClassData(name); *             return defineClass(name, b, 0, b.length); *         } * *         private byte[] loadClassData(String name) { *             // load the class data from the connection *             &nbsp;.&nbsp;.&nbsp;. *         } *     } * </pre></blockquote> * * <h4> <a name="name">Binary names</a> </h4> * * <p> Any class name provided as a {@link String} parameter to methods in * <tt>ClassLoader</tt> must be a binary name as defined by * <cite>The Java&trade; Language Specification</cite>. * * <p> Examples of valid class names include: * <blockquote><pre> *   "java.lang.String" *   "javax.swing.JSpinner$DefaultEditor" *   "java.security.KeyStore$Builder$FileBuilder$1" *   "java.net.URLClassLoader$3$1" * </pre></blockquote> * * @see      #resolveClass(Class) * @since 1.0 */public abstract class ClassLoader {     private static native void registerNatives();    static {        registerNatives();    }     // The parent class loader for delegation    // Note: VM hardcoded the offset of this field, thus all new fields    // must be added *after* it.    private final ClassLoader parent;     /**     * Encapsulates the set of parallel capable loader types.     */    private static class ParallelLoaders {        private ParallelLoaders() {}         // the set of parallel capable loader types        private static final Set<Class<? extends ClassLoader>> loaderTypes =            Collections.newSetFromMap(                new WeakHashMap<Class<? extends ClassLoader>, Boolean>());        static {            synchronized (loaderTypes) { loaderTypes.add(ClassLoader.class); }        }         /**         * Registers the given class loader type as parallel capabale.         * Returns {@code true} is successfully registered; {@code false} if         * loader's super class is not registered.         */        static boolean register(Class<? extends ClassLoader> c) {            synchronized (loaderTypes) {                if (loaderTypes.contains(c.getSuperclass())) {                    // register the class loader as parallel capable                    // if and only if all of its super classes are.                    // Note: given current classloading sequence, if                    // the immediate super class is parallel capable,                    // all the super classes higher up must be too.                    loaderTypes.add(c);                    return true;                } else {                    return false;                }            }        }         /**         * Returns {@code true} if the given class loader type is         * registered as parallel capable.         */        static boolean isRegistered(Class<? extends ClassLoader> c) {            synchronized (loaderTypes) {                return loaderTypes.contains(c);            }        }    }     // Maps class name to the corresponding lock object when the current    // class loader is parallel capable.    // Note: VM also uses this field to decide if the current class loader    // is parallel capable and the appropriate lock object for class loading.    private final ConcurrentHashMap<String, Object> parallelLockMap;     // Hashtable that maps packages to certs    private final Map <String, Certificate[]> package2certs;     // Shared among all packages with unsigned classes    private static final Certificate[] nocerts = new Certificate[0];     // The classes loaded by this class loader. The only purpose of this table    // is to keep the classes from being GC'ed until the loader is GC'ed.    private final Vector<Class<?>> classes = new Vector<>();     // The "default" domain. Set as the default ProtectionDomain on newly    // created classes.    private final ProtectionDomain defaultDomain =        new ProtectionDomain(new CodeSource(null, (Certificate[]) null),                             null, this, null);     // The initiating protection domains for all classes loaded by this loader    private final Set<ProtectionDomain> domains;     // Invoked by the VM to record every loaded class with this loader.    void addClass(Class c) {        classes.addElement(c);    }     // The packages defined in this class loader.  Each package name is mapped    // to its corresponding Package object.    // @GuardedBy("itself")    private final HashMap<String, Package> packages = new HashMap<>();     private static Void checkCreateClassLoader() {        SecurityManager security = System.getSecurityManager();        if (security != null) {            security.checkCreateClassLoader();        }        return null;    }     private ClassLoader(Void unused, ClassLoader parent) {        this.parent = parent;        if (ParallelLoaders.isRegistered(this.getClass())) {            parallelLockMap = new ConcurrentHashMap<>();            package2certs = new ConcurrentHashMap<>();            domains =                Collections.synchronizedSet(new HashSet<ProtectionDomain>());            assertionLock = new Object();        } else {            // no finer-grained lock; lock on the classloader instance            parallelLockMap = null;            package2certs = new Hashtable<>();            domains = new HashSet<>();            assertionLock = this;        }    }     /**     * Creates a new class loader using the specified parent class loader for     * delegation.     *     * <p> If there is a security manager, its {@link     * SecurityManager#checkCreateClassLoader()     * <tt>checkCreateClassLoader</tt>} method is invoked.  This may result in     * a security exception.  </p>     *     * @param  parent     *         The parent class loader     *     * @throws  SecurityException     *          If a security manager exists and its     *          <tt>checkCreateClassLoader</tt> method doesn't allow creation     *          of a new class loader.     *     * @since  1.2     */    protected ClassLoader(ClassLoader parent) {        this(checkCreateClassLoader(), parent);    }     /**     * Creates a new class loader using the <tt>ClassLoader</tt> returned by     * the method {@link #getSystemClassLoader()     * <tt>getSystemClassLoader()</tt>} as the parent class loader.     *     * <p> If there is a security manager, its {@link     * SecurityManager#checkCreateClassLoader()     * <tt>checkCreateClassLoader</tt>} method is invoked.  This may result in     * a security exception.  </p>     *     * @throws  SecurityException     *          If a security manager exists and its     *          <tt>checkCreateClassLoader</tt> method doesn't allow creation     *          of a new class loader.     */    protected ClassLoader() {        this(checkCreateClassLoader(), getSystemClassLoader());    }     // -- Class --     /**     * Loads the class with the specified <a href="#name">binary name</a>.     * This method searches for classes in the same manner as the {@link     * #loadClass(String, boolean)} method.  It is invoked by the Java virtual     * machine to resolve class references.  Invoking this method is equivalent     * to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,     * false)</tt>}.  </p>     *     * @param  name     *         The <a href="#name">binary name</a> of the class     *     * @return  The resulting <tt>Class</tt> object     *     * @throws  ClassNotFoundException     *          If the class was not found     */    public Class<?> loadClass(String name) throws ClassNotFoundException {        return loadClass(name, false);    }     /**     * Loads the class with the specified <a href="#name">binary name</a>.  The     * default implementation of this method searches for classes in the     * following order:     *     * <p><ol>     *     *   <li><p> Invoke {@link #findLoadedClass(String)} to check if the class     *   has already been loaded.  </p></li>     *     *   <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method     *   on the parent class loader.  If the parent is <tt>null</tt> the class     *   loader built-in to the virtual machine is used, instead.  </p></li>     *     *   <li><p> Invoke the {@link #findClass(String)} method to find the     *   class.  </p></li>     *     * </ol>     *     * <p> If the class was found using the above steps, and the     * <tt>resolve</tt> flag is true, this method will then invoke the {@link     * #resolveClass(Class)} method on the resulting <tt>Class</tt> object.     *     * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link     * #findClass(String)}, rather than this method.  </p>     *     * <p> Unless overridden, this method synchronizes on the result of     * {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method     * during the entire class loading process.     *     * @param  name     *         The <a href="#name">binary name</a> of the class     *     * @param  resolve     *         If <tt>true</tt> then resolve the class     *     * @return  The resulting <tt>Class</tt> object     *     * @throws  ClassNotFoundException     *          If the class could not be found     */    protected Class<?> loadClass(String name, boolean resolve)        throws ClassNotFoundException    {        synchronized (getClassLoadingLock(name)) {            // First, check if the class has already been loaded            Class c = findLoadedClass(name);            if (c == null) {                long t0 = System.nanoTime();                try {                    if (parent != null) {                        c = parent.loadClass(name, false);                    } else {                        c = findBootstrapClassOrNull(name);                    }                } catch (ClassNotFoundException e) {                    // ClassNotFoundException thrown if class not found                    // from the non-null parent class loader                }                 if (c == null) {                    // If still not found, then invoke findClass in order                    // to find the class.                    long t1 = System.nanoTime();                    c = findClass(name);                     // this is the defining class loader; record the stats                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);                    sun.misc.PerfCounter.getFindClasses().increment();                }            }            if (resolve) {                resolveClass(c);            }            return c;        }    }     /**     * Returns the lock object for class loading operations.     * For backward compatibility, the default implementation of this method     * behaves as follows. If this ClassLoader object is registered as     * parallel capable, the method returns a dedicated object associated     * with the specified class name. Otherwise, the method returns this     * ClassLoader object. </p>     *     * @param  className     *         The name of the to-be-loaded class     *     * @return the lock for class loading operations     *     * @throws NullPointerException     *         If registered as parallel capable and <tt>className</tt> is null     *     * @see #loadClass(String, boolean)     *     * @since  1.7     */    protected Object getClassLoadingLock(String className) {        Object lock = this;        if (parallelLockMap != null) {            Object newLock = new Object();            lock = parallelLockMap.putIfAbsent(className, newLock);            if (lock == null) {                lock = newLock;            }        }        return lock;    }     // This method is invoked by the virtual machine to load a class.    private Class loadClassInternal(String name)        throws ClassNotFoundException    {        // For backward compatibility, explicitly lock on 'this' when        // the current class loader is not parallel capable.        if (parallelLockMap == null) {            synchronized (this) {                 return loadClass(name);            }        } else {            return loadClass(name);        }    }     // Invoked by the VM after loading class with this loader.    private void checkPackageAccess(Class cls, ProtectionDomain pd) {        final SecurityManager sm = System.getSecurityManager();        if (sm != null) {            final String name = cls.getName();            final int i = name.lastIndexOf('.');            if (i != -1) {                AccessController.doPrivileged(new PrivilegedAction<Void>() {                    public Void run() {                        sm.checkPackageAccess(name.substring(0, i));                        return null;                    }                }, new AccessControlContext(new ProtectionDomain[] {pd}));            }        }        domains.add(pd);

Lines 1–500 of 2204.