非常详细的ClassLoader介绍:http://www.javashuo.com/article/p-vliilzaq-b.html
在此下载jdk7源码:http://jdk7src.sourceforge.net/
三个内建ClassLoader
BootstrapClassLoader,ExtClassLoader, AppClassLoader
Bootstrap ClassLoader 最顶层的加载类,主要加载核心类库,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。
Extention ClassLoader 扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。
Appclass Loader也称为SystemAppClass 加载当前应用的classpath的所有类。
System.out.println(System.getProperty("sun.boot.class.path")); System.out.println(System.getProperty("java.ext.dirs")); System.out.println(System.getProperty("java.class.path"));
每个类加载器都有一个父加载器(不是父类)
public abstract class ClassLoader { // 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; private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent; ... } protected ClassLoader() { this(checkCreateClassLoader(), getSystemClassLoader()); } 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; } } protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError { return defineClass(name, b, off, len, null); } protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) throws ClassFormatError { protectionDomain = preDefineClass(name, protectionDomain); Class c = null; String source = defineClassSourceLocation(protectionDomain); try { c = defineClass1(name, b, off, len, protectionDomain, source); } catch (ClassFormatError cfe) { c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, source); } postDefineClass(c, protectionDomain); return c; } protected final Class<?> defineClass(String name, java.nio.ByteBuffer b, ProtectionDomain protectionDomain) throws ClassFormatError { int len = b.remaining(); // Use byte[] if not a direct ByteBufer: if (!b.isDirect()) { if (b.hasArray()) { return defineClass(name, b.array(), b.position() + b.arrayOffset(), len, protectionDomain); } else { // no array, or read-only array byte[] tb = new byte[len]; b.get(tb); // get bytes out of byte buffer. return defineClass(name, tb, 0, len, protectionDomain); } } protectionDomain = preDefineClass(name, protectionDomain); Class c = null; String source = defineClassSourceLocation(protectionDomain); try { c = defineClass2(name, b, b.position(), len, protectionDomain, source); } catch (ClassFormatError cfe) { byte[] tb = new byte[len]; b.get(tb); // get bytes out of byte buffer. c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe, source); } postDefineClass(c, protectionDomain); return c; } protected final Class<?> findSystemClass(String name) throws ClassNotFoundException { ClassLoader system = getSystemClassLoader(); if (system == null) { if (!checkName(name)) throw new ClassNotFoundException(name); Class cls = findBootstrapClass(name); if (cls == null) { throw new ClassNotFoundException(name); } return cls; } return system.loadClass(name); } @CallerSensitive public final ClassLoader getParent() { if (parent == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(parent, Reflection.getCallerClass()); } return parent; } @CallerSensitive public static ClassLoader getSystemClassLoader() { initSystemClassLoader(); if (scl == null) { return null; } SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; } private static synchronized void initSystemClassLoader() { if (!sclSet) { if (scl != null) throw new IllegalStateException("recursive invocation"); sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); if (l != null) { Throwable oops = null; scl = l.getClassLoader(); try { scl = AccessController.doPrivileged( new SystemClassLoaderAction(scl)); } catch (PrivilegedActionException pae) { oops = pae.getCause(); if (oops instanceof InvocationTargetException) { oops = oops.getCause(); } } if (oops != null) { if (oops instanceof Error) { throw (Error) oops; } else { // wrap the exception throw new Error(oops); } } } sclSet = true; } } private static ClassLoader scl; }
parent指示父加载器,loadClass函数显示:
先查找是否已加载 -> 调用父加载器的loadClass -> findClass -> resolveClass
ExtClassLoader和AppClassLoader都继承于URLClassLoader
public class URLClassLoader extends SecureClassLoader implements Closeable { /* The search path for classes and resources */ private final URLClassPath ucp; public URLClassLoader(URL[] urls) { super(); // this is to make the stack depth consistent with 1.1 SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkCreateClassLoader(); } ucp = new URLClassPath(urls); this.acc = AccessController.getContext(); } protected Class<?> findClass(final String name) throws ClassNotFoundException { try { return AccessController.doPrivileged( new PrivilegedExceptionAction<Class>() { public Class run() throws ClassNotFoundException { String path = name.replace('.', '/').concat(".class"); Resource res = ucp.getResource(path, false); if (res != null) { try { return defineClass(name, res); } catch (IOException e) { throw new ClassNotFoundException(name, e); } } else { throw new ClassNotFoundException(name); } } }, acc); } catch (java.security.PrivilegedActionException pae) { throw (ClassNotFoundException) pae.getException(); } } }
从path中读取class文件,加载成类
如果需要实现一些自定义的类加载功能,就需要自定义一下加载类:
编写一个类继承自ClassLoader抽象类。
复写它的findClass()方法。
在findClass()方法中调用defineClass()。
举例:
public class DiskClassLoader extends ClassLoader { private String mLibPath; public DiskClassLoader(String path) { // TODO Auto-generated constructor stub mLibPath = path; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // TODO Auto-generated method stub String fileName = getFileName(name); File file = new File(mLibPath,fileName); try { FileInputStream is = new FileInputStream(file); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int len = 0; try { while ((len = is.read()) != -1) { bos.write(len); } } catch (IOException e) { e.printStackTrace(); } byte[] data = bos.toByteArray(); is.close(); bos.close(); return defineClass(name,data,0,data.length); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return super.findClass(name); } //获取要加载 的class文件名 private String getFileName(String name) { // TODO Auto-generated method stub int index = name.lastIndexOf('.'); if(index == -1){ return name+".class"; }else{ return name.substring(index+1)+".class"; } } }
Thread源码
public class Thread implements Runnable { /* The context ClassLoader for this thread */ private ClassLoader contextClassLoader; public void setContextClassLoader(ClassLoader cl) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("setContextClassLoader")); } contextClassLoader = cl; } public ClassLoader getContextClassLoader() { if (contextClassLoader == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { ClassLoader.checkClassLoaderPermission(contextClassLoader, Reflection.getCallerClass()); } return contextClassLoader; } }
每个Thread都有一个相关联的ClassLoader,默认是AppClassLoader。并且子线程默认使用父线程的ClassLoader除非子线程特别设置。