ClassLoader中文类加载器,java编写出来的是.java文件,然后编译成.class文件,而ClassLoader就是把class文件加载到jvm内存中;但jvm启动时,通过不同的类加载器,动态的加载class文件;java比较重要的三类加载器Bootstrap ClassLoader、 Extention ClassLoader、Appclass Loader。

Bootstrap ClassLoader、 Extention ClassLoader、Appclass Loader这三个类加载器分别负责加载不同路径下的文件

它是最顶级的类加载,主要加载载核心类库,其路径为%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等,而这个路径是可以通过jvm启动参数-Xbootclasspath来设置

扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。

当前应用的classpath的所有类

 

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5.  
  6. package sun.misc;
  7. import java.io.File;
  8. import java.io.IOException;
  9. import java.net.MalformedURLException;
  10. import java.net.URL;
  11. import java.net.URLClassLoader;
  12. import java.net.URLStreamHandler;
  13. import java.net.URLStreamHandlerFactory;
  14. import java.security.AccessControlContext;
  15. import java.security.AccessController;
  16. import java.security.CodeSource;
  17. import java.security.PermissionCollection;
  18. import java.security.PrivilegedAction;
  19. import java.security.PrivilegedActionException;
  20. import java.security.PrivilegedExceptionAction;
  21. import java.security.ProtectionDomain;
  22. import java.security.cert.Certificate;
  23. import java.util.HashSet;
  24. import java.util.StringTokenizer;
  25. import java.util.Vector;
  26. import sun.net.www.ParseUtil;
  27. public class Launcher {
  28. private static URLStreamHandlerFactory factory = new Launcher.Factory();
  29. private static Launcher launcher = new Launcher();
      
  30. private static String bootClassPath = System.getProperty("sun.boot.class.path");


  31.   private ClassLoader loader;
  32. private static URLStreamHandler fileHandler;
  33. public static Launcher getLauncher() {
  34. return launcher;
  35. }
  36. public Launcher() {
  37. Launcher.ExtClassLoader var1;
  38. try {
  39. var1 = Launcher.ExtClassLoader.getExtClassLoader();
  40. } catch (IOException var10) {
  41. throw new InternalError("Could not create extension class loader");
  42. }
  43. try {
  44. this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
  45. } catch (IOException var9) {
  46. throw new InternalError("Could not create application class loader");
  47. }
  48. Thread.currentThread().setContextClassLoader(this.loader);
  49. String var2 = System.getProperty("java.security.manager");
  50. if (var2 != null) {
  51. SecurityManager var3 = null;
  52. if (!"".equals(var2) && !"default".equals(var2)) {
  53. try {
  54. var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
  55. } catch (IllegalAccessException var5) {
  56. ;
  57. } catch (InstantiationException var6) {
  58. ;
  59. } catch (ClassNotFoundException var7) {
  60. ;
  61. } catch (ClassCastException var8) {
  62. ;
  63. }
  64. } else {
  65. var3 = new SecurityManager();
  66. }
  67. if (var3 == null) {
  68. throw new InternalError("Could not create SecurityManager: " + var2);
  69. }
  70. System.setSecurityManager(var3);
  71. }
  72. }
  73. public ClassLoader getClassLoader() {
  74. return this.loader;
  75. }
  76. public static URLClassPath getBootstrapClassPath() {
  77. return Launcher.BootClassPathHolder.bcp;
  78. }

  79.   ………………………………
  80. }

 

1. 没有看到 Bootstrap ClassLoader,只有bootClassPath,这个应该就是顶级类加载器的加载路径;

2.Launcher 先初始化了Extention ClassLoader ,然后把传入它实例再初始化AppClassLoader。

  1. static class ExtClassLoader extends URLClassLoader {
  2. public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
            
           //获取加载的文件,进入getExtDirs可以看到加载的文件路径
    String var0 = System.getProperty("java.ext.dirs")
  1. final File[] var0 = getExtDirs();
  2. try {
  3. return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
  4. public Launcher.ExtClassLoader run() throws IOException {
  5. int var1 = var0.length;
  6. for(int var2 = 0; var2 < var1; ++var2) {
  7. MetaIndex.registerDirectory(var0[var2]);
  8. }
  9.               //创建类加载
  10. return new Launcher.ExtClassLoader(var0);
  11. }
  12. });
  13. } catch (PrivilegedActionException var2) {
  14. throw (IOException)var2.getException();
  15. }
  16. }
  17. void addExtURL(URL var1) {
  18. super.addURL(var1);
  19. }
  20.       
  21. public ExtClassLoader(File[] var1) throws IOException {
           
            //调用父类方法创建,留意到第二个参数为null,这个参数是父加载器,预测ExtClassLoader是没有父加载器的
            super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
  1. }
  2. private static File[] getExtDirs() {
  3. String var0 = System.getProperty("java.ext.dirs");
  4. File[] var1;
  5. if (var0 != null) {
  6. StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
  7. int var3 = var2.countTokens();
  8. var1 = new File[var3];
  9. for(int var4 = 0; var4 < var3; ++var4) {
  10. var1[var4] = new File(var2.nextToken());
  11. }
  12. } else {
  13. var1 = new File[0];
  14. }
  15. return var1;
  16. }
  17. private static URL[] getExtURLs(File[] var0) throws IOException {
  18. Vector var1 = new Vector();
  19. for(int var2 = 0; var2 < var0.length; ++var2) {
  20. String[] var3 = var0[var2].list();
  21. if (var3 != null) {
  22. for(int var4 = 0; var4 < var3.length; ++var4) {
  23. if (!var3[var4].equals("meta-index")) {
  24. File var5 = new File(var0[var2], var3[var4]);
  25. var1.add(Launcher.getFileURL(var5));
  26. }
  27. }
  28. }
  29. }
  30. URL[] var6 = new URL[var1.size()];
  31. var1.copyInto(var6);
  32. return var6;
  33. }
  34. public String findLibrary(String var1) {
  35. var1 = System.mapLibraryName(var1);
  36. URL[] var2 = super.getURLs();
  37. File var3 = null;
  38. for(int var4 = 0; var4 < var2.length; ++var4) {
  39. File var5 = (new File(var2[var4].getPath())).getParentFile();
  40. if (var5 != null && !var5.equals(var3)) {
  41. String var6 = VM.getSavedProperty("os.arch");
  42. File var7;
  43. if (var6 != null) {
  44. var7 = new File(new File(var5, var6), var1);
  45. if (var7.exists()) {
  46. return var7.getAbsolutePath();
  47. }
  48. }
  49. var7 = new File(var5, var1);
  50. if (var7.exists()) {
  51. return var7.getAbsolutePath();
  52. }
  53. }
  54. var3 = var5;
  55. }
  56. return null;
  57. }
  58. private static AccessControlContext getContext(File[] var0) throws IOException {
  59. PathPermissions var1 = new PathPermissions(var0);
  60. ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[])null), var1);
  61. AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2});
  62. return var3;
  63. }
  64. static {
  65. ClassLoader.registerAsParallelCapable();
  66. }
  67. }




看看ExtenTionClassLoader初始化做了什么 

从上面可以看到ExtClassLoader extends URLClassLoader,初始化ExtClassLoader先读取java.ext.dirs路径(D:\java7\jre\lib\ext;C:\Windows\Sun\Java\lib\ext)下的文件,然后调用URLClassLoader.supper()–>

SecureClassLoader.supper()–>ClassLoader.supper()–>方法创建,因为传入的parent是null,可以看到ExtClassLoader 没有父加载器的;简单说就是加载java.ext.dirs的文件创建了个无父加载器的类加载器。

 

  1. public static void main(String[] args) {
  2. System.out.println(System.getProperty("java.ext.dirs"));
  3. }
  4. /*
  5. D:\java7\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
  6. */

    /*
    URLClassLoader extends SecureClassLoader implements Closeable
  1. */
  1. public URLClassLoader(URL[] urls, ClassLoader parent,
    URLStreamHandlerFactory factory) {
    super(parent);
    // this is to make the stack depth consistent with 1.1
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
    security.checkCreateClassLoader();
    }
    ucp = new URLClassPath(urls, factory);
    acc = AccessController.getContext();
    }

 /******************************************************************************/

  /*

  SecureClassLoader extends ClassLoader

  */

  1. protected SecureClassLoader(ClassLoader parent) {
    super(parent);
    // this is to make the stack depth consistent with 1.1
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
    security.checkCreateClassLoader();
    }
    initialized = true;
    }

  /******************************************************************************/

  1. /*
  1. ClassLoader
  1. */
  1. protected ClassLoader(ClassLoader parent) {
    this(checkCreateClassLoader(), parent);
    }
  1. 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;
    }
    }

 

  1. static class AppClassLoader extends URLClassLoader {
  2. public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
  3. final String var1 = System.getProperty("java.class.path");
  4. final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
  5. return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
  6. public Launcher.AppClassLoader run() {
  7. URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
  8. return new Launcher.AppClassLoader(var1x, var0);
  9. }
  10. });
  11. }
  12. AppClassLoader(URL[] var1, ClassLoader var2) {
  13. super(var1, var2, Launcher.factory);
  14. }
  15. public Class loadClass(String var1, boolean var2) throws ClassNotFoundException {
  16. int var3 = var1.lastIndexOf(46);
  17. if (var3 != -1) {
  18. SecurityManager var4 = System.getSecurityManager();
  19. if (var4 != null) {
  20. var4.checkPackageAccess(var1.substring(0, var3));
  21. }
  22. }
  23. return super.loadClass(var1, var2);
  24. }
  25. protected PermissionCollection getPermissions(CodeSource var1) {
  26. PermissionCollection var2 = super.getPermissions(var1);
  27. var2.add(new RuntimePermission("exitVM"));
  28. return var2;
  29. }
  30. private void appendToClassPathForInstrumentation(String var1) {
  31. assert Thread.holdsLock(this);
  32. super.addURL(Launcher.getFileURL(new File(var1)));
  33. }
  34. private static AccessControlContext getContext(File[] var0) throws MalformedURLException {
  35. PathPermissions var1 = new PathPermissions(var0);
  36. ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[])null), var1);
  37. AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2});
  38. return var3;
  39. }
  40. static {
  41. ClassLoader.registerAsParallelCapable();
  42. }
  43. }

 

从上面看APPClassLoader也是继承URLClassLoader,与ExtClassLoader不同的是,

1.读取的路径是java.class.path

2.把ExtClassLoader的实例作为APPClassLoader的父加载器,也就是说APPClassLoader的父类加载器是ExtClassLoader

3.加载顺序Bootstrap ClassLoader 到 ExtClassLoader 到 APPClassLoader

首先我们先要明确一点是父加载器并不是父类,我们可以通过下面的代码看到

  1. public class MyClassLoader extends URLClassLoader {
  2. public MyClassLoader(URL[] repositories) {
  3. super(repositories);
  4. }
  5. public MyClassLoader(URL[] repositories, ClassLoader parent) {
  6. super(repositories, parent);
  7. }
  8. }
  9.   public static void main(String[] args) {
  10. ClassLoader cl = MyClassLoader.class.getClassLoader();
  11. System.out.println("ClassLoader is:"+cl.toString());
  12. System.out.println("ClassLoader\'s parent is:"+cl.getParent().toString());
  13. // System.out.println("ClassLoader\'s grand father is:"+cl.getParent().getParent().toString());
  14. }
  15. ClassLoader is:sun.misc.Launcher$AppClassLoader@31fc6b2
  16. ClassLoader's parent is:sun.misc.Launcher$ExtClassLoader@1b2dd1b8

 

1.MyClassLoader 继承URLClassLoader,但是可以到店MyClassLoader的父加载器是AppClassLoader

2.AppClassLoader 的父加载器是ExtClassLoader,这个在上面分析初始化的APPClassLoader的时候,就可以看到传入ExtClassLoader的实例作为它的加载器,那么ExtClassLoader的父加载器上面初始时是null,我们可以验证一下

  1. public static void main(String[] args) {
  2. ClassLoader cl = MyClassLoader.class.getClassLoader();
  3. // System.out.println("ClassLoader is:"+cl.toString());
  4. // System.out.println("ClassLoader\'s parent is:"+cl.getParent().toString());
  5. System.out.println("ClassLoader\'s grand father is:"+cl.getParent().getParent().toString());
  6. }
  7. Exception in thread "main" java.lang.NullPointerException
  8. at com.suntek.vdm.gw.util.NotifyHandler.main(NotifyHandler.java:373)

 

从上面的代码可以看到,我们的上面是对的ExtClassLoader的父加载器的确是null.

3.那么其他的没有指定父加载器的ClassLoader的父加载器是什么呢?从上面的代码我们可以看到MyClassLoader的的是APPClassLoader,那么这是为什么呢?难道没有指定父加载器的ClassLoader的默认是APP

  1. /*
  2. 这ClassLoader是没有指定父加载器创建方法
  3. */
  4. protected ClassLoader() {
  5. this(checkCreateClassLoader(), getSystemClassLoader());
  6. }
  7. //这里我们可以看到getSytemClassLoader()这个方法获取父加载器
  8. private ClassLoader(Void unused, ClassLoader parent) {
  9. this.parent = parent;
  10. if (ParallelLoaders.isRegistered(this.getClass())) {
  11. parallelLockMap = new ConcurrentHashMap<>();
  12. package2certs = new ConcurrentHashMap<>();
  13. domains =
  14. Collections.synchronizedSet(new HashSet<ProtectionDomain>());
  15. assertionLock = new Object();
  16. } else {
  17. // no finer-grained lock; lock on the classloader instance
  18. parallelLockMap = null;
  19. package2certs = new Hashtable<>();
  20. domains = new HashSet<>();
  21. assertionLock = this;
  22. }
  23. }
  24.   //看到return的是scl,而scl赋值是initSystemClassLoader()方法
  25. public static ClassLoader getSystemClassLoader() {
  26. initSystemClassLoader();
  27. if (scl == null) {
  28. return null;
  29. }
  30. SecurityManager sm = System.getSecurityManager();
  31. if (sm != null) {
  32. checkClassLoaderPermission(scl, Reflection.getCallerClass());
  33. }
  34. return scl;
  35. }
  36.   //真相就在这里了,就是Launcher的getClassLoader(),而Luancher初始化的前面有看过了,也可以往下看
  37. private static synchronized void initSystemClassLoader() {
  38. if (!sclSet) {
  39. if (scl != null)
  40. throw new IllegalStateException("recursive invocation");
  41. sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  42. if (l != null) {
  43. Throwable oops = null;
  44. scl = l.getClassLoader();
  45. try {
  46. scl = AccessController.doPrivileged(
  47. new SystemClassLoaderAction(scl));
  48. } catch (PrivilegedActionException pae) {
  49. oops = pae.getCause();
  50. if (oops instanceof InvocationTargetException) {
  51. oops = oops.getCause();
  52. }
  53. }
  54. if (oops != null) {
  55. if (oops instanceof Error) {
  56. throw (Error) oops;
  57. } else {
  58. // wrap the exception
  59. throw new Error(oops);
  60. }
  61. }
  62. }
  63. sclSet = true;
  64. }
  65. }
  66. //这个是Launcher对的getClassLoader,然后在看看下面的图,明白了,就是APPClassLoader
  67. public ClassLoader getClassLoader() {
  68. return this.loader;
  69. }

一层层往下最终APPClassLoader作为默认的ClassLoader;

也就是没有指定的父加载器的默认为是APPClassLoader;

有了父加载器的概念之后,我们就可以开始双亲委托这个玩意了!这部分,发现个哥们写得不错 https://blog.csdn.net/briblue/article/details/54973413,于是就复制了!

 

一个类加载器查找class和resource时,是通过“委托模式”进行的,它首先判断这个class是不是已经加载成功,如果没有的话它并不是自己进行查找,而是先通过父加载器,然后递归下去,直到Bootstrap ClassLoader,如果Bootstrap classloader找到了,直接返回,如果没有找到,则一级一级返回,最后到达自身去查找这些对象。这种机制就叫做双亲委托。 
整个流程可以如下图所示: 

大家可以看到2根箭头,蓝色的代表类加载器向上委托的方向,如果当前的类加载器没有查询到这个class对象已经加载就请求父加载器(不一定是父类)进行操作,然后以此类推。直到Bootstrap ClassLoader。如果Bootstrap ClassLoader也没有加载过此class实例,那么它就会从它指定的路径中去查找,如果查找成功则返回,如果没有查找成功则交给子类加载器,也就是ExtClassLoader,这样类似操作直到终点,也就是我上图中的红色箭头示例。 
用序列描述一下: 
1. 一个AppClassLoader查找资源时,先看看缓存是否有,缓存有从缓存中获取,否则委托给父加载器。 
2. 递归,重复第1部的操作。 
3. 如果ExtClassLoader也没有加载过,则由Bootstrap ClassLoader出面,它首先查找缓存,如果没有找到的话,就去找自己的规定的路径下,也就是sun.mic.boot.class下面的路径。找到就返回,没有找到,让子加载器自己去找。 
4. Bootstrap ClassLoader如果没有查找成功,则ExtClassLoader自己在java.ext.dirs路径中去查找,查找成功就返回,查找不成功,再向下让子加载器找。 
5. ExtClassLoader查找不成功,AppClassLoader就自己查找,在java.class.path路径下查找。找到就返回。如果没有找到就让子类找,如果没有子类会怎么样?抛出各种异常。

上面的序列,详细说明了双亲委托的加载流程。我们可以发现委托是从下向上,然后具体查找过程却是自上至下。

 

这里要说一下ExtClassLoader 这个是没有父加载器,就通过BootStrapClassLoader这个来查找的,下面这个代码的ClassLoader这个类的方法,

  1. protected Class<?> loadClass(String name, boolean resolve)
  2. throws ClassNotFoundException
  3. {
  4. synchronized (getClassLoadingLock(name)) {
  5. // First, check if the class has already been loaded
           // 首先到缓存寻找
  6. Class c = findLoadedClass(name);
  7. if (c == null) {
  8. long t0 = System.nanoTime();
  9. try {
  10. if (parent != null) {
                  //如果父加强是空,往上找
  11. c = parent.loadClass(name, false);
  12. } else {
                  //否则就通过BootStrapClassLoader找,也就应该是ExtClassLoader
  13. c = findBootstrapClassOrNull(name);
  14. }
  15. } catch (ClassNotFoundException e) {
  16. // ClassNotFoundException thrown if class not found
  17. // from the non-null parent class loader
  18. }
  19. if (c == null) {
  20. // If still not found, then invoke findClass in order
  21. // to find the class.
  22. long t1 = System.nanoTime();
  23. c = findClass(name);
  24. // this is the defining class loader; record the stats
  25. sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
  26. sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
  27. sun.misc.PerfCounter.getFindClasses().increment();
  28. }
  29. }
  30. if (resolve) {
  31. resolveClass(c);
  32. }
  33. return c;
  34. }
  35. }

了解我们可以自己写一个简单的加载类

  1. public class MyClassLoader extends URLClassLoader {
  2. public MyClassLoader(URL[] repositories) {
  3. super(repositories);
  4. }
  5. public MyClassLoader(URL[] repositories, ClassLoader parent) {
  6. super(repositories, parent);
  7. }
  8. }
  9. public final class MyClassLoaderFactory {
  10. public static ClassLoader createClassLoader(File unpacked[], final ClassLoader parent)
  11. throws Exception {
  12. Set<URL> set = new LinkedHashSet<URL>();
  13. if (unpacked != null) {
  14. for (int i = 0; i < unpacked.length; i++) {
  15. File file = unpacked[i];
  16. if (!file.exists() || !file.canRead()){
  17. continue;
  18. }
  19. file = new File(file.getCanonicalPath() + File.separator);
  20. URL url = file.toURI().toURL();
  21. set.add(url);
  22. }
  23. }
  24. final URL[] array = set.toArray(new URL[set.size()]);
  25. return AccessController.doPrivileged(new PrivilegedAction<MyClassLoader>() {
  26. @Override
  27. public MyClassLoader run() {
  28. if (parent == null){
  29. return new MyClassLoader(array);
  30. }else {
  31. return new MyClassLoader(array, parent);
  32. }
  33. }
  34. });
  35. }
  36. }


  37. private static void startWithClassloader(String path) throws Exception {
  38. String classPath= path;
  39. File[] packed = new File[] { new File(path) };
  40. ClassLoader catalinaLoader = MyClassLoaderFactory.createClassLoader(null, packed, null);
  41. Thread.currentThread().setContextClassLoader(catalinaLoader);
  42. Class<?> startupClass = catalinaLoader.loadClass(MAIN_CLASS);
  43. Object startupInstance = startupClass.newInstance();
  44. Method method = startupInstance.getClass().getMethod("start");
  45. method.invoke(startupInstance);
  46. }

 

一步一步来吧,首先自定义一个MyClassLoader类继承了URlClassLoader,再对比一下AppClassLoader 的创建,可以说基本一样;

a.获取路径的File[] 文件;

b.然后就调用了AccessController 的native <T> T doPrivileged(PrivilegedAction<T> action),而关于这个方法的说法,网友们是这么说的一个调用者在调用doPrivileged方法时,可被标识为 “特权”。在做访问控制决策时,如果checkPermission方法遇到一个通过doPrivileged调用而被表示为 “特权”的调用者,并且没有上下文自变量,checkPermission方法则将终止检查。如果那个调用者的域具有特定的许可,则不做进一步检查,checkPermission安静地返回,表示那个访问请求是被允许的;如果那个域没有特定的许可,则象通常一样,一个异常被抛出

c.调用福利的supper方法创建

 

a.在java的应用中,每个线程都有一个contextClassLoad,而充init()方法可以看到,默认是父线程的上下文类加载器,当月我们也可以通过Thread.currentThread().setContextClassLoader(catalinaLoader)来设置;

b.这个上下文的加载器的作用简单的说,就是当这个线程加载某些类时,通过这加载器进行加载;

c.网友说法:

每个运行中的线程都有一个成员contextClassLoader,用来在运行时动态地载入其它类
系统默认的contextClassLoader是systemClassLoader,所以一般而言java程序在执行时可以使用JVM自带的类、$JAVA_HOME/jre/lib/ext/中的类和$CLASSPATH/中的类
可以使用Thread.currentThread().setContextClassLoader(…);更改当前线程的contextClassLoader,来改变其载入类的行为
ClassLoader被组织成树形,一般的工作原理是:
1) 线程需要用到某个类,于是contextClassLoader被请求来载入该类
2) contextClassLoader请求它的父ClassLoader来完成该载入请求
3) 如果父ClassLoader无法载入类,则contextClassLoader试图自己来载入
注意:WebApp?ClassLoader的工作原理和上述有少许不同:
它先试图自己载入类(在ContextBase?/WEB-INF/…中载入类),如果无法载入,再请求父ClassLoader完成

  1. public
  2. class Thread implements Runnable {
  3. /* Make sure registerNatives is the first thing <clinit> does. */
  4. private static native void registerNatives();
  5. static {
  6. registerNatives();
  7. }
  8. private char name[];
  9. private int priority;
  10. private Thread threadQ;
  11. private long eetop;
  12. /* Whether or not to single_step this thread. */
  13. private boolean single_step;
  14. /* Whether or not the thread is a daemon thread. */
  15. private boolean daemon = false;
  16. /* JVM state */
  17. private boolean stillborn = false;
  18. /* What will be run. */
  19. private Runnable target;
  20. /* The group of this thread */
  21. private ThreadGroup group;
  22. /* The context ClassLoader for this thread */
  23. private ClassLoader contextClassLoader;




  24. ………………
  25. }

 

  1. private void init(ThreadGroup g, Runnable target, String name,
  2. long stackSize, AccessControlContext acc) {
  3. if (name == null) {
  4. throw new NullPointerException("name cannot be null");
  5. }
  6. this.name = name.toCharArray();
  7. Thread parent = currentThread();
  8. SecurityManager security = System.getSecurityManager();
  9. if (g == null) {
  10. /* Determine if it's an applet or not */
  11.  
  12. /* If there is a security manager, ask the security manager
  13. what to do. */
  14. if (security != null) {
  15. g = security.getThreadGroup();
  16. }
  17. /* If the security doesn't have a strong opinion of the matter
  18. use the parent thread group. */
  19. if (g == null) {
  20. g = parent.getThreadGroup();
  21. }
  22. }
  23. /* checkAccess regardless of whether or not threadgroup is
  24. explicitly passed in. */
  25. g.checkAccess();
  26. /*
  27. * Do we have the required permissions?
  28. */
  29. if (security != null) {
  30. if (isCCLOverridden(getClass())) {
  31. security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  32. }
  33. }
  34. g.addUnstarted();
  35. this.group = g;
  36. this.daemon = parent.isDaemon();
  37. this.priority = parent.getPriority();
  38. if (security == null || isCCLOverridden(parent.getClass()))
  39. this.contextClassLoader = parent.getContextClassLoader();
  40. else
  41. this.contextClassLoader = parent.contextClassLoader;
  42. this.inheritedAccessControlContext =
  43. acc != null ? acc : AccessController.getContext();
  44. this.target = target;
  45. setPriority(priority);
  46. if (parent.inheritableThreadLocals != null)
  47. this.inheritableThreadLocals =
  48. ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
  49. /* Stash the specified stack size in case the VM cares */
  50. this.stackSize = stackSize;
  51. /* Set thread ID */
  52. tid = nextThreadID();
  53. }

 

 

版权声明:本文为nedhome原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/nedhome/p/9053132.html