zoukankan      html  css  js  c++  java
  • 分析Java的类加载器与ClassLoader(二):classpath与查找类字节码的顺序,分析ExtClassLoader与AppClassLoader的源码

    先回顾一下classpath

    classpath的作用:

            classpath的作用是指定查找类的路径:当使用java命令执行一个类(类中的main方法)时,会从classpath中进行查找这个类。 

    指定classpath的方式一: 
            设置环境变量CLASSPATH,多个路径之间使用英文的分号隔开,也可以指定为jar包路径。 
             示例:CLASSPATH=c:/myclasses/;c/mylib/aa.jar;c:/mylib/bb.jar;. 
             注意:在Windows中不区分大小写,所以指定的环境变量名为classpath或是ClassPath都一样。 

    指定classpath的方式二: 
             在执行java命令时通过-classpath参数指定。 
             示例:java -classpath c:/myclasses/;c:/mylib/aa.jar cn.itcast.MainApp 
             注意:这样就会只是用这个参数指定的classpath,找不到类就报错,不会使用CLASSPATH环境变量! 

    指定classpath时各个路径的顺序: 
            试验的结论是 按classpath中指定的顺序,先从前面的路径中查找,如果找不到,在从下一个路径中查找,直到找到类字节码或是报NoClassDefFoundError。 
    另外一种指定类路径方式: 
            把类字节码文件打成jar包,并放到JRE的lib/ext/目录下,这样在执行时就可以直接找到这个类而不需要指定classpath了。 

    类加载器与classpath

    从上一个文章中我们知道了类加载器默认使用三个: 
    1,Bootstrap ClassLoader,启动类加载器,负责加载核心Class(即所有java.*开头的Class)。 
    2,Extension ClassLoader,扩展类加载器,负责加载存放在JRE的lib/ext/目录下的jar包中的Class。 
    3,Application ClassLoader,应用程序类加载器,负责加载应用程序自身的类(CLASSPATH目录中的Class)。 

    分析ExtClassLoader

            Extension ClassLoader负责加载扩展类路径中的类(默认为JRE的lib/ext/目录) ,也就是说只要把jar包放到这个目录中,就可以直接使用里面的类字节码而不需要指定classpath !注意这要求一定要在这个目录中放jar包,直接把.class文件放到这个目录中不行。分析一下源码(sun.misc.Launcher$ExtClassLoader类):

    static class ExtClassLoader extends URLClassLoader {
      private File[] dirs;
    
    
      // 先看这个方法
      public static ExtClassLoader getExtClassLoader() throws IOException {
        // 调用getExtDirs()方法获取配置的扩展类路径
        final File[] dirs = getExtDirs();
        try {
          // 使用getExtDirs()方法返回的路径生成一个新的ClassLoader实例
          return (ExtClassLoader) AccessController.doPrivileged(new PrivilegedExceptionAction() {
            public Object run() throws IOException {
              int len = dirs.length;
              for (int i = 0; i < len; i++) {
                MetaIndex.registerDirectory(dirs[i]);
              }
              return new ExtClassLoader(dirs);
            }
          });
        } catch (java.security.PrivilegedActionException e) {
          throw (IOException) e.getException();
        }
      }
    
    
      // 再看这个方法
      private static File[] getExtDirs() {
        // 获取配置的扩展类路径
        String s = System.getProperty("java.ext.dirs");
        File[] dirs;
        if (s != null) {
          StringTokenizer st = new StringTokenizer(s, File.pathSeparator);
          int count = st.countTokens();
          dirs = new File[count];
          for (int i = 0; i < count; i++) {
            dirs[i] = new File(st.nextToken());
          }
        } else {
          dirs = new File[0];
        }
        return dirs;
      }
      
      // 其他代码略
      ...
    }

             Application ClassLoader负责加载CLASSPATH目录中的Class ,也就是说classpath是给这个类加载器用的。分析一下源码(sun.misc.Launcher$AppClassLoader类): 

    static class AppClassLoader extends URLClassLoader {
    
    
      public static ClassLoader getAppClassLoader(final ClassLoader extcl) throws IOException {
        // 获取配置的classpath路径
        // 注1:可以通过设置classpath环境变量改变java.class.path的值。
        // 注2:也可以在程序中使用System.setProperty("java.class.path", "newpath")改变java.class.path的值。
        final String s = System.getProperty("java.class.path");
        final File[] path = (s == null) ? new File[0] : getClassPath(s);
    
    
        // 使用classpath中的路径生成一个新的ClassLoader实例并返回
        return (AppClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
          public Object run() {
            URL[] urls = (s == null) ? new URL[0] : pathToURLs(path);
            return new AppClassLoader(urls, extcl);
          }
        });
      }
    
    
      // 其他代码略
      ...
    }

    当AppClassLoader遇上ExtClassLoader

            如果JRE的lib/ext/目录下的jar包有某个类,我们指定的classpath中也有这个类,会怎么样呢?想想类加载查找类字节码的策略!结论是会执行lib/ext/xx.jar中的类! 因为类加载器使用委托模式进行类加载,并且ExtClassLoader是AppClassLoader的上级,所以AppClassLoader会先让ExtClassLoader加载。如果父的类加载器没有找到,自己才会加载。 

    结论: 
    1,把jar包放到扩展类路径中就可以直接使用其中的类(默认是JRE的lib/ext/目录)
    2,classpath是给AppClassLoader配置的。 
    3,如果扩展类路径中有某个类,classpath中也有这个类,则会使用扩展类路径中的类。 

    http://www.tuicool.com/articles/bQFnqmi

  • 相关阅读:
    LeetCode OJ 112. Path Sum
    LeetCode OJ 226. Invert Binary Tree
    LeetCode OJ 100. Same Tree
    LeetCode OJ 104. Maximum Depth of Binary Tree
    LeetCode OJ 111. Minimum Depth of Binary Tree
    LeetCode OJ 110. Balanced Binary Tree
    apache-jmeter-3.1的简单压力测试使用方法(下载和安装)
    JMeter入门教程
    CentOS6(CentOS7)设置静态IP 并且 能够上网
    分享好文:分享我在阿里8年,是如何一步一步走向架构师的
  • 原文地址:https://www.cnblogs.com/softidea/p/3888806.html
Copyright © 2011-2022 走看看