jdkclassloader.java

来自「java jdk 1.4的源码」· Java 代码 · 共 227 行

JAVA
227
字号
/* * @(#)JDKClassLoader.java	1.20 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. *//* * Licensed Materials - Property of IBM * RMI-IIOP v1.0 * Copyright IBM Corp. 1998 1999  All Rights Reserved * * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */package com.sun.corba.se.internal.util;import java.io.IOException;import java.io.*;import java.util.*;import java.lang.ref.WeakReference;import java.lang.reflect.*;import java.security.AccessController;import java.security.PrivilegedAction;/** *  Utility method for crawling call stack to load class */class JDKClassLoader {    private static final JDKClassLoaderCache classCache        = new JDKClassLoaderCache();    private static final Class[] NO_ARGS = new Class[] {};    // latestUserDefinedLoader() is a private static method    // in java.io.ObjectInputStream in JDK 1.3 and 1.4.    // We use reflection in a doPrivileged block to get a    // Method reference and make it accessible.    //    // We should be very careful about what happens when this    // method no longer exists!  Right now, Errors will be    // thrown.    private static final Method latestUserDefinedLoaderMethod        = JDKClassLoader.getLatestUserDefinedLoaderMethod();    private static Method getLatestUserDefinedLoaderMethod() {        return (Method) AccessController.doPrivileged(new PrivilegedAction() {            public Object run() {                Method result = null;                try {                    // Try to dig up the method we want                    Class io = java.io.ObjectInputStream.class;                    result                        = io.getDeclaredMethod("latestUserDefinedLoader",                                                NO_ARGS);                    result.setAccessible(true);                } catch (NoSuchMethodException nsme) {                    // Throw Errors right now.  This is a serious problem                    throw new Error("java.io.ObjectInputStream"                                    + " latestUserDefinedLoader "                                    + nsme);                }                return result;            }        });    }    // Uses reflection and the final static Method (obtained    // by reflection at class load time) to call the    // latestUserDefinedLoader native code.    private static ClassLoader getLatestUserDefinedLoader()    {        try {            // Invoke the ObjectInputStream.latestUserDefinedLoader method            return (ClassLoader)latestUserDefinedLoaderMethod.invoke(null,                                                                      NO_ARGS);        } catch (InvocationTargetException ite) {            throw new Error("java.io.ObjectInputStream"                            + " latestUserDefinedLoader "                            + ite);        } catch (IllegalAccessException iae) {            throw new Error("java.io.ObjectInputStream"                            + " latestUserDefinedLoader "                            + iae);        }    }    static Class loadClass(Class aClass, String className)	throws ClassNotFoundException {        // Maintain the same error semantics as Class.forName()        if (className == null) {            throw new NullPointerException();        }        if (className.length() == 0) {            throw new ClassNotFoundException();        }        // It would be nice to bypass JDKClassLoader's attempts completely        // if it's known that the latest user defined ClassLoader will        // fail.        //        // Otherwise, we end up calling Class.forName here as well as in        // the next step in JDKBridge.  That can take a long time depending        // on the length of the classpath.        // Note: Looking at the only place in JDKBridge where this code        // is invoked, it is clear that aClass will always be null.        ClassLoader loader;        if (aClass != null) {            loader = aClass.getClassLoader();        } else {            loader = getLatestUserDefinedLoader();        }        // See createKey for a description of what's involved        Object key = classCache.createKey(className, loader);        if (classCache.knownToFail(key)) {            throw new ClassNotFoundException(className);        } else {            try {                // Loading this class with the call stack                // loader isn't known to fail, so try                // to load it.                return Class.forName(className, false, loader);            } catch(ClassNotFoundException cnfe) {                // Record that we failed to find the class                // with this particular loader.  This way, we won't                // waste time looking with this loader, again.                classCache.recordFailure(key);                throw cnfe;            }        }    }	    /**     * Private cache implementation specific to JDKClassLoader.     */    private static class JDKClassLoaderCache    {        // JDKClassLoader couldn't find the class with the located        // ClassLoader.  Note this in our cache so JDKClassLoader        // can abort early next time.        public final void recordFailure(Object key) {            cache.put(key, JDKClassLoaderCache.KNOWN_TO_FAIL);        }        // Factory for a key (CacheKey is an implementation detail        // of JDKClassLoaderCache).        //        // A key currently consists of the class name as well as        // the latest user defined class loader, so it's fairly        // expensive to create.        public final Object createKey(String className, ClassLoader latestLoader) {                      return new CacheKey(className, latestLoader);        }        // Determine whether or not this combination of class name        // and ClassLoader is known to fail.        public final boolean knownToFail(Object key) {            return cache.get(key) == JDKClassLoaderCache.KNOWN_TO_FAIL;        }        // Synchronized WeakHashMap        private final Map cache            = Collections.synchronizedMap(new WeakHashMap());        // Cache result used to mark the caches when there is        // no way JDKClassLoader could succeed with the given        // key        private static final Object KNOWN_TO_FAIL = new Object();        // Key consisting of the class name and the latest        // user defined class loader        private static class CacheKey        {            String className;            ClassLoader loader;                    public CacheKey(String className, ClassLoader loader) {                this.className = className;                this.loader = loader;            }            // Try to incorporate both class name and loader            // into the hashcode            public int hashCode() {                if (loader == null)                    return className.hashCode();                else                    return className.hashCode() ^ loader.hashCode();            }            public boolean equals(Object obj) {                try {                    // WeakHashMap may compare null keys                    if (obj == null)                        return false;                    CacheKey other = (CacheKey)obj;                    // I've made a decision to actually compare the                    // loader references.  I don't want a case when                    // two loader instances override their equals                    // methods and only compare code base.                    //                    // This way, at worst, our performance will                    // be slower, but we know we'll do the correct                    // loading.                    return (className.equals(other.className) &&                            loader == other.loader);                                    } catch (ClassCastException cce) {                    return false;                }            }        }    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?