类加载器
1. 启动类加载器
加载 JAVA_HOME\lib 下的 类文件。rt.jar
2.扩展类加载器和应用程序类加载器,这两个加载器都继承自
1)public abstract class java.lang.ClassLoader 类
都是
public class sun.misc.Launcher 的静态内部类
2)static class ExtClassLoader extends URLClassLoader 作为扩展类加载器,主要加载 JAVA_HOME\lib\ext 下的 类
3)static class AppClassLoader extends URLClassLoader 作为 用户应用程序类加载器,主要加载 用户 classpath 下的 class文件,可通过
ClassLoader 的静态方法 public static ClassLoader getSystemClassLoader() 获取
4)类加载器入口方法
ClassLoader:
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
ClassLoader:
// 该方法在 jdk1.2 之前,都是 作为 重写的。jdk1.2之后 引入 双亲委派模式,加入了 findClass作为 自己的类加载器重写的主要方法
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;
}
}
* @since 1.2
*/
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
// 同时,在jdk1.2 的 Thread 类中引入了 线程上下文类加载器
* @since 1.2
*/
public void setContextClassLoader(ClassLoader cl) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
contextClassLoader = cl;
}
自定义类加载器,需要重写 findClass 方法,需要用 ClassLoader 提供的 defineClass 将读取到的 字节数组 写入内存 返回 Class 对象
* @since 1.1
*/
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(name, b, off, len, null);
}
线程上线文类加载器的应用:在 Apache 的 common log 中有用到。
org.apache.commons.logging.LogFactory
public static LogFactory getFactory() throws LogConfigurationException { // Identify the class loader we will be using ClassLoader contextClassLoader = getContextClassLoaderInternal();
private static ClassLoader getContextClassLoaderInternal() throws LogConfigurationException { return (ClassLoader)AccessController.doPrivileged( new PrivilegedAction() { public Object run() { return directGetContextClassLoader(); } }); }
protected static ClassLoader directGetContextClassLoader() throws LogConfigurationException {
ClassLoader classLoader = null;
try {
classLoader = Thread.currentThread().getContextClassLoader();
} catch (SecurityException ex) {
/**
* getContextClassLoader() throws SecurityException when
* the context class loader isn't an ancestor of the
* calling class's class loader, or if security
* permissions are restricted.
*
* We ignore this exception to be consistent with the previous
* behavior (e.g. 1.1.3 and earlier).
*/
// ignore
}
// Return the selected class loader
return classLoader;
}