ClassLoader是什么

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

Java中的类加载器

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

Bootstrap CLassloder

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

Extention ClassLoader

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

AppClassLoader

当前应用的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.  
  8. import java.io.File;
  9. import java.io.IOException;
  10. import java.net.MalformedURLException;
  11. import java.net.URL;
  12. import java.net.URLClassLoader;
  13. import java.net.URLStreamHandler;
  14. import java.net.URLStreamHandlerFactory;
  15. import java.security.AccessControlContext;
  16. import java.security.AccessController;
  17. import java.security.CodeSource;
  18. import java.security.PermissionCollection;
  19. import java.security.PrivilegedAction;
  20. import java.security.PrivilegedActionException;
  21. import java.security.PrivilegedExceptionAction;
  22. import java.security.ProtectionDomain;
  23. import java.security.cert.Certificate;
  24. import java.util.HashSet;
  25. import java.util.StringTokenizer;
  26. import java.util.Vector;
  27. import sun.net.www.ParseUtil;
  28.  
  29. public class Launcher {
  30. private static URLStreamHandlerFactory factory = new Launcher.Factory();
  31. private static Launcher launcher = new Launcher();
      
  32. private static String bootClassPath = System.getProperty("sun.boot.class.path");
  33.   private ClassLoader loader;
  34. private static URLStreamHandler fileHandler;
  35.  
  36. public static Launcher getLauncher() {
  37. return launcher;
  38. }
  39.  
  40. public Launcher() {
  41. Launcher.ExtClassLoader var1;
  42. try {
  43. var1 = Launcher.ExtClassLoader.getExtClassLoader();
  44. } catch (IOException var10) {
  45. throw new InternalError("Could not create extension class loader");
  46. }
  47.  
  48. try {
  49. this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
  50. } catch (IOException var9) {
  51. throw new InternalError("Could not create application class loader");
  52. }
  53.  
  54. Thread.currentThread().setContextClassLoader(this.loader);
  55. String var2 = System.getProperty("java.security.manager");
  56. if (var2 != null) {
  57. SecurityManager var3 = null;
  58. if (!"".equals(var2) && !"default".equals(var2)) {
  59. try {
  60. var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
  61. } catch (IllegalAccessException var5) {
  62. ;
  63. } catch (InstantiationException var6) {
  64. ;
  65. } catch (ClassNotFoundException var7) {
  66. ;
  67. } catch (ClassCastException var8) {
  68. ;
  69. }
  70. } else {
  71. var3 = new SecurityManager();
  72. }
  73.  
  74. if (var3 == null) {
  75. throw new InternalError("Could not create SecurityManager: " + var2);
  76. }
  77.  
  78. System.setSecurityManager(var3);
  79. }
  80.  
  81. }
  82.  
  83. public ClassLoader getClassLoader() {
  84. return this.loader;
  85. }
  86.  
  87. public static URLClassPath getBootstrapClassPath() {
  88. return Launcher.BootClassPathHolder.bcp;
  89. }

  90.   ………………………………
  91.  
  92. }

从以上源码可以看到

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

看看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. /*
  6. D:\java7\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
  7. */
  8.  
  9. /*
    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;
    }
    }

看看APPClassLoader初始化做了什么

  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.  
  13. AppClassLoader(URL[] var1, ClassLoader var2) {
  14. super(var1, var2, Launcher.factory);
  15. }
  16.  
  17. public Class loadClass(String var1, boolean var2) throws ClassNotFoundException {
  18. int var3 = var1.lastIndexOf(46);
  19. if (var3 != -1) {
  20. SecurityManager var4 = System.getSecurityManager();
  21. if (var4 != null) {
  22. var4.checkPackageAccess(var1.substring(0, var3));
  23. }
  24. }
  25.  
  26. return super.loadClass(var1, var2);
  27. }
  28.  
  29. protected PermissionCollection getPermissions(CodeSource var1) {
  30. PermissionCollection var2 = super.getPermissions(var1);
  31. var2.add(new RuntimePermission("exitVM"));
  32. return var2;
  33. }
  34.  
  35. private void appendToClassPathForInstrumentation(String var1) {
  36. assert Thread.holdsLock(this);
  37.  
  38. super.addURL(Launcher.getFileURL(new File(var1)));
  39. }
  40.  
  41. private static AccessControlContext getContext(File[] var0) throws MalformedURLException {
  42. PathPermissions var1 = new PathPermissions(var0);
  43. ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[])null), var1);
  44. AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2});
  45. return var3;
  46. }
  47.  
  48. static {
  49. ClassLoader.registerAsParallelCapable();
  50. }
  51. }

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

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

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

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

父加载器

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

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

一层层往下最终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.  
  20. if (c == null) {
  21. // If still not found, then invoke findClass in order
  22. // to find the class.
  23. long t1 = System.nanoTime();
  24. c = findClass(name);
  25.  
  26. // this is the defining class loader; record the stats
  27. sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
  28. sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
  29. sun.misc.PerfCounter.getFindClasses().increment();
  30. }
  31. }
  32. if (resolve) {
  33. resolveClass(c);
  34. }
  35. return c;
  36. }
  37. }

自定义类加载器

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

  1. public class MyClassLoader extends URLClassLoader {
  2.  
  3. public MyClassLoader(URL[] repositories) {
  4. super(repositories);
  5. }
  6.  
  7. public MyClassLoader(URL[] repositories, ClassLoader parent) {
  8. super(repositories, parent);
  9. }
  10.  
  11. }
  12.  
  13. public final class MyClassLoaderFactory {
  14.  
  15. public static ClassLoader createClassLoader(File unpacked[], final ClassLoader parent)
  16. throws Exception {
  17.  
  18. Set<URL> set = new LinkedHashSet<URL>();
  19.  
  20. if (unpacked != null) {
  21. for (int i = 0; i < unpacked.length; i++) {
  22. File file = unpacked[i];
  23. if (!file.exists() || !file.canRead()){
  24. continue;
  25. }
  26. file = new File(file.getCanonicalPath() + File.separator);
  27. URL url = file.toURI().toURL();
  28. set.add(url);
  29. }
  30. }
  31.  
  32. final URL[] array = set.toArray(new URL[set.size()]);
  33. return AccessController.doPrivileged(new PrivilegedAction<MyClassLoader>() {
  34.  
  35. @Override
  36. public MyClassLoader run() {
  37. if (parent == null){
  38. return new MyClassLoader(array);
  39. }else {
  40. return new MyClassLoader(array, parent);
  41. }
  42. }
  43. });
  44. }
  45. }
  46.  
  47. private static void startWithClassloader(String path) throws Exception {
  48. String classPath= path;
  49. File[] packed = new File[] { new File(path) };
  50. ClassLoader catalinaLoader = MyClassLoaderFactory.createClassLoader(null, packed, null);
  51. Thread.currentThread().setContextClassLoader(catalinaLoader);
  52.  
  53. Class<?> startupClass = catalinaLoader.loadClass(MAIN_CLASS);
  54. Object startupInstance = startupClass.newInstance();
  55. Method method = startupInstance.getClass().getMethod("start");
  56. method.invoke(startupInstance);
  57. }

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

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

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

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

Thread.currentThread().setContextClassLoader(catalinaLoader) 这个句有什么用??

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.  
  9. private char name[];
  10. private int priority;
  11. private Thread threadQ;
  12. private long eetop;
  13.  
  14. /* Whether or not to single_step this thread. */
  15. private boolean single_step;
  16.  
  17. /* Whether or not the thread is a daemon thread. */
  18. private boolean daemon = false;
  19.  
  20. /* JVM state */
  21. private boolean stillborn = false;
  22.  
  23. /* What will be run. */
  24. private Runnable target;
  25.  
  26. /* The group of this thread */
  27. private ThreadGroup group;
  28.  
  29. /* The context ClassLoader for this thread */
  30. private ClassLoader contextClassLoader;
  31.  
  32.  
  33. ………………
  34.  
  35. }
  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.  
  7. this.name = name.toCharArray();
  8.  
  9. Thread parent = currentThread();
  10. SecurityManager security = System.getSecurityManager();
  11. if (g == null) {
  12. /* Determine if it's an applet or not */
  13.  
  14. /* If there is a security manager, ask the security manager
  15. what to do. */
  16. if (security != null) {
  17. g = security.getThreadGroup();
  18. }
  19.  
  20. /* If the security doesn't have a strong opinion of the matter
  21. use the parent thread group. */
  22. if (g == null) {
  23. g = parent.getThreadGroup();
  24. }
  25. }
  26.  
  27. /* checkAccess regardless of whether or not threadgroup is
  28. explicitly passed in. */
  29. g.checkAccess();
  30.  
  31. /*
  32. * Do we have the required permissions?
  33. */
  34. if (security != null) {
  35. if (isCCLOverridden(getClass())) {
  36. security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  37. }
  38. }
  39.  
  40. g.addUnstarted();
  41.  
  42. this.group = g;
  43. this.daemon = parent.isDaemon();
  44. this.priority = parent.getPriority();
  45. if (security == null || isCCLOverridden(parent.getClass()))
  46. this.contextClassLoader = parent.getContextClassLoader();
  47. else
  48. this.contextClassLoader = parent.contextClassLoader;
  49. this.inheritedAccessControlContext =
  50. acc != null ? acc : AccessController.getContext();
  51. this.target = target;
  52. setPriority(priority);
  53. if (parent.inheritableThreadLocals != null)
  54. this.inheritableThreadLocals =
  55. ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
  56. /* Stash the specified stack size in case the VM cares */
  57. this.stackSize = stackSize;
  58.  
  59. /* Set thread ID */
  60. tid = nextThreadID();
  61. }

最后通过反射把程序运行起来

一个题目

  1. /**
  2. * a.加载->校验->准备->初始化->使用->卸载(准备和初始化)
  3. * b.父类静态->本身静态->父类变量和代码块->父类构造器->本身变量和代码块->本身构造器
  4. * c.静态只会加载一次,静态变量一开始会在准备阶段赋值默认值,如st = null, flag = false;
  5. * c.而st = new StaticTest()这步骤被镶嵌到static StaticTest st = new StaticTest();
  6. * d.开始执行new StaticTest(),因为静态变量都已经初始化,因此进入:本身变量和代码块->本身构造器
  7. * e.结束new StaticTest(),进入下一个静态变量初始化System.out.println("2");再下一个static boolean flag = true;
  8. * f.执行方法staticFunction();
  9. */
  10. public class StaticTest {
  11. public static void main(String[] args) {
  12. staticFunction();
  13. }
  14.  
  15. {
  16. System.out.println("1");
  17. }
  18.  
  19. static StaticTest st = new StaticTest();
  20.  
  21. static {
  22. System.out.println("2");
  23. }
  24.  
  25. StaticTest() {
  26. System.out.println("3");
  27. double temp = 3*0.1;
  28. if (temp == a){
  29. System.out.println(a+","+flag);
  30. }else {
  31. System.out.println(a+","+flag);
  32. }
  33.  
  34. }
  35.  
  36. private static void staticFunction(){
  37. if (flag){
  38. System.out.println("4");
  39. }else {
  40. System.out.println("5");
  41.  
  42. }
  43. }
  44. double a=0.3;
  45. static boolean flag = true;
  46. }

1
3
0.3,false
2
4

  1.  

ClassLoader那事儿的更多相关文章

  1. Proxy那点事儿

    全文转载,原文地址:Proxy 那点事儿 Proxy,也就是"代理"了.意思就是,你不用去做,别人代替你去处理.比如说:赚钱方面,我就是我老婆的 Proxy:带小孩方面,我老婆就是 ...

  2. 一文带你深扒ClassLoader内核,揭开它的神秘面纱!

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」. 如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力! 前言 Clas ...

  3. java 编程基础 Class对象 反射:动态代理 和AOP:java.lang.reflect.Proxy:(Proxy.newProxyInstance(newProxyInstance​(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h))

    为什么我们使用动态代理 静态代理会让类变多了,多了代理类,工作量变大了,且不易扩展.比如我们上节课的例子,要实现不同的扩展方法就要编写不同的代理类,非常麻烦.   Proxy类的使用规则 Proxy提 ...

  4. 聊聊 Netty 那些事儿之 Reactor 在 Netty 中的实现(创建篇)

    本系列Netty源码解析文章基于 4.1.56.Final版本 在上篇文章<聊聊Netty那些事儿之从内核角度看IO模型>中我们花了大量的篇幅来从内核角度详细讲述了五种IO模型的演进过程以 ...

  5. 说说Makefile那些事儿

    说说Makefile那些事儿 |扬说|透过现象看本质 工作至今,一直对Makefile半知半解.突然某天幡然醒悟,觉得此举极为不妥,只得洗心革面从头学来,以前许多不明觉厉之处顿时茅塞顿开,想想好记性不 ...

  6. 总结iOS开发中的断点续传那些事儿

    前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...

  7. 使用自定义 classloader 的正确姿势

    详细的原理就不多说了,网上一大把, 但是, 看了很多很多, 即使看了jdk 源码, 说了罗里吧嗦, 还是不很明白: 到底如何正确自定义ClassLoader, 需要注意什么 ExtClassLoade ...

  8. Atitti 载入类的几种方法    Class.forName ClassLoader.loadClass  直接new

    Atitti 载入类的几种方法    Class.forName ClassLoader.loadClass  直接new 1.1. 载入类的几种方法    Class.forName ClassLo ...

  9. setTimeout那些事儿

    一.setTimeout那些事儿之单线程 一直以来,大家都在说Javascript是单线程,浏览器无论在什么时候,都且只有一个线程在运行JavaScript程序. 但是,不知道大家有疑问没——就是我们 ...

随机推荐

  1. asp.net的Request.ServerVariables参数说明

    Request.ServerVariables["SERVER_NAME"] '获取服务器IPRequest.ServerVariables["HTTP_REFERER& ...

  2. ztree搜索节点并展开

    web <div class="zTreeC"> <div class="searchL" lay-filter="searchL& ...

  3. Webstorm 2017.3激活破解

    之前尝试过各种激活破解办法,不过随着版本的不断升级,激活信息都失效了(毕竟咱不是通过正常途径激活的),只能重新激活.而且难度越来越大,记得早先网上有人分享激活码,激活的server地址,破解程序等等, ...

  4. 伺服电机&旋转变压器&光电编码器

    旋转变压器与光电编码器是目前伺服领域应用最广的测量传感器. 一.伺服系统 又称为随动系统,精确的跟随或者复现某个过程的反馈系统. 使物体的位置.方位.状态等输出被控量能够跟随目标(设定)的任意变化的自 ...

  5. kerberos环境下spark消费kafka写入到Hbase

    一.准备环境: 创建Kafka Topic和HBase表 1. 在kerberos环境下创建Kafka Topic 1.1 因为kafka默认使用的协议为PLAINTEXT,在kerberos环境下需 ...

  6. 网站通信协议升级到HTTPS&HTTP2

    为何要升级到HTTPS和HTTP2? http://baijiahao.baidu.com/s?id=1602041305989767011&wfr=spider&for=pc htt ...

  7. python_while

    while 格式 while 条件 : pass 使用 while True : print("精忠报国") print("粉红的回忆") print(&quo ...

  8. 转:SVN 版本服务器搭配全过程详解(含服务端、客户端)

    1.为什么要用VisualSVN Server,而不用Subversion? 回答: 因为如果直接使用Subversion,那么在Windows 系统上,要想让它随系统启动,就要封装SVN Serve ...

  9. Windows之常用命令

    1. 重启/关机 shutdown命令 #关机 shutdown -s -t -f #重启 shutdown -r -t //30秒之后,重启 00是立即 #注销 shutdown -l -t #休眠 ...

  10. mongodb解决只能本地连接不能远程连接问题

    本机windows7 ,装了vagrant盒子,并在盒子上装了mongodb服务,本机连接虚拟机时连不上. 解决方法: 修改虚拟机上 mongodb.conf 文件,将bind_ip = 127.0. ...