ClassLoader类加载器

关于ClassLoader原理网上简介颇多,但是讲的好的,能让人简而易懂的理解的,个人觉得以下这个片博客写的不错。

java虚拟机原理图解 5. JVM类加载器机制与类加载过程

为了理解本文,我从代码角度来分析JVM加载机制和类加载过程

首先:

  BootStrapClassLoader----引导类加载器---C++编写,封装入JVM

  ExtClassLoader----------扩展类加载器---Launcher内部类

  AppClassLoader----------应用类加载器/系统类加载器---Launcher内部

当我们在IJ或者eclipserun一个带main方法的类时或者在linuxjava batchmain

run之前,我们的java虚拟机是关闭的状态。run虚拟机开启,BootStrapClassLoader会加载{JAVA_HOME}/jre/lib下的jar包,

其中有一个rt.jar的包中,我们会找到一个sun.misc.Launcher类,既然BootStrapClassLoader加载rt.jar必然会加载Launcher,

这里我贴了源代码:

 

package sun.misc;

import ...

public class Launcher {
    private static URLStreamHandlerFactory factory = new Launcher.Factory();
  //我们可以看出这个单例模式,私有化launcher,当BootStrap加载Launcher时,自动创建Launcher的实例
private static Launcher launcher = new Launcher(); private static String bootClassPath = System.getProperty("sun.boot.class.path"); private ClassLoader loader; private static URLStreamHandler fileHandler;   //单例模式提供的public get方法 public static Launcher getLauncher() { return launcher; }   //构造方法,会实例化内部类ExtClassLoaderAppClassLoader public Launcher() { Launcher.ExtClassLoader var1; try {
        //实例化ExtClassLoader var1
= Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try {
        //实例化AppClassLoader
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } Thread.currentThread().setContextClassLoader(this.loader); String var2 = System.getProperty("java.security.manager"); if (var2 != null) { SecurityManager var3 = null; if (!"".equals(var2) && !"default".equals(var2)) { try { var3 = (SecurityManager)this.loader.loadClass(var2).newInstance(); System.setSecurityManager(var3); } }

 

AppClassLoader and ExtClassLoader拥有相同的以下继承关系:

AppClassLoader extends URLClassLoader extends SecureClassLoader extends ClassLoader

ExtClassLoader extends URLClassLoader extends SecureClassLoader extends ClassLoader

ClassLoader是个抽象类,但是有构造方法,如下

1 //代码我以略掉大部分
2 public abstract class ClassLoader {
3     private final ClassLoader parent;
4 
5     private ClassLoader(Void unused, ClassLoader parent) {
6         this.parent = parent;
7      }
8 }

AppClassLoaderExtClassLoader实例化这个部分我也贴出代码:

 

 1 static class AppClassLoader extends URLClassLoader {
 2         final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
 3 
 4         public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
 5             final String var1 = System.getProperty("java.class.path");
 6             final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
 7             return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
 8                 public Launcher.AppClassLoader run() {
 9                     URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
              //此处返回的对象根据java多态性回调用Classloader抽象类构造方法parent传值为var0,ExtClassLoader
10 return new Launcher.AppClassLoader(var1x, var0); 11 } 12 }); 13 } 14 15 AppClassLoader(URL[] var1, ClassLoader var2) { 16 super(var1, var2, Launcher.factory); 17 this.ucp.initLookupCache(this); 18 } 19 20 public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException { 21 int var3 = var1.lastIndexOf(46); 22 if (var3 != -1) { 23 SecurityManager var4 = System.getSecurityManager(); 24 if (var4 != null) { 25 var4.checkPackageAccess(var1.substring(0, var3)); 26 } 27 } 28 29 if (this.ucp.knownToNotExist(var1)) { 30 Class var5 = this.findLoadedClass(var1); 31 if (var5 != null) { 32 if (var2) { 33 this.resolveClass(var5); 34 } 35 36 return var5; 37 } else { 38 throw new ClassNotFoundException(var1); 39 } 40 } else { 41 return super.loadClass(var1, var2); 42 } 43 }
 1 static class ExtClassLoader extends URLClassLoader {
 2         public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
 3             final File[] var0 = getExtDirs();
 4 
 5             try {
 6                 return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
 7                     public Launcher.ExtClassLoader run() throws IOException {
 8                         int var1 = var0.length;
 9 
10                         for(int var2 = 0; var2 < var1; ++var2) {
11                             MetaIndex.registerDirectory(var0[var2]);
12                         }
13               //此处返回的对象根据java多态性回调用Classloader抽象类构造方法,其parent传值为null。
14                         return new Launcher.ExtClassLoader(var0);
15                     }
16                 });
17             } catch (PrivilegedActionException var2) {
18                 throw (IOException)var2.getException();
19             }
20         }

 至此JVM类加载器初始化完毕。然后loader.loadClass();

此时我们根据类加载规则,去加载main类,如果发现有main()方法,就开始直接执行,直到exit。

我们需要注意的是,类加载器加载一个类时,并不是去读代码看看那些类需要加载,这里涉及到最重要的东西那就是:

Import,因为我们需要的类都是引入进来的,引入包直接加载就好了。

 

setContextClassLoader可以打破双亲加载机制。典型应用---tomcat启动类BootStrap定义了三个自定义加载器,
catalinaClassLoader
commonClassLoader
sharedClassLoader
......

 

 

 

  

posted on 2018-01-16 19:41  剑姬  阅读(141)  评论(0编辑  收藏  举报

导航