欢迎您光临本小站。希望您在这里可以找到自己想要的信息。。。

JAVA Launcher简析

java water 2341℃ 0评论

JAVA Launcher简析
sun.misc.Launcher类是java的入口,在启动java应用的时候会首先创建Launcher类,创建Launcher类的时候回准备应用程序运行中需要的类加载器。

一、ClassLoader
Launcher作为JAVA应用的入口,根据双亲委派模型,Laucher是由JVM创建的,它类加载器应该是BootStrapClassLoader, 这是一个C++编写的类加载器,是java应用体系中最顶层的类加载器,负责加载JVM需要的一些类库(/lib)。可以通过一个简单的代码验证一下我们的想法。

public class App {
public static void main(String[] args) {
ClassLoader classLoader = Launcher.class.getClassLoader();
}
}
这里的classLoader是null,说明Launcher确实是BootstrapClassLoader加载的,那么我们就会非常好奇,ExtClassLoader是什么时候创建的呢?翻看一下Launcher的构造器的代码。

public Launcher() {
    sun.misc.Launcher.ExtClassLoader extClassLoader;
    try {
        extClassLoader = sun.misc.Launcher.ExtClassLoader.getExtClassLoader();
    } catch (IOException var10) {
        throw new InternalError("Could not create extension class loader", var10);
    }
    try {
        this.loader = sun.misc.Launcher.AppClassLoader.getAppClassLoader(extClassLoader);
    } catch (IOException var9) {
        throw new InternalError("Could not create application class loader", var9);
    }

    Thread.currentThread().setContextClassLoader(this.loader);
}


Launcher在创建的时候,第一件事情就是获取ExtClassLoader, ExtClassLoader在JVM中是一个单例, 创建过程也是通过获取环境变量来获取ext加载的目录,生成一个ExtClassLoader,ExtClassLoader是URLClassLoader的子类。

   public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
        if (instance == null) {
            Class clazz = Launcher.ExtClassLoader.class;
            synchronized(Launcher.ExtClassLoader.class) {
                if (instance == null) {
                    instance = createExtClassLoader();
                }
            }
        }
        return instance;
    }


在获取ExtClassLoader之后,以此作为父类加载器创建一个 sun.misc.Launcher.AppClassLoader, AppClassLoader的加载路径是java.class.path标记的路径,相同的,AppClassLoader也是URLClassLoader的子类。最终会将当前线程的上下文类加载器设置为AppClassLoader。
通过上述分析,当我们需要获取当前应用程序的AppClassLoader或者ExtClassLoader的时候,可以直接使用Launcher来访问。

public class App {
public static void main(String[] args) {
ClassLoader appClassLoader = Launcher.getLauncher().getClassLoader();
ClassLoader extClassLoader = appClassLoader.getParent();
}
}
二、Thread上下文ClassLoader的思考
java程序并不是一个单独的可执行文件,而是由一组.class文件组成。在应用程序启动的时候,并不是所有的类都会被加载,一个类被加载的时候会使用引用这个类的那个类的加载器来加载,也就是xxx.class.getClassLoader()。但是在日常使用的时候,还有一种是通过Thread的上限文获取类加载器。
在java中为什么需要上下文类加载器呢,这个就是一个非常有意思的问题。 我们都知道java类加载的双亲委派模型,在加载一个类的时候,会优先委派给父类加载器,这样保证不会出现类被重复加载,也保证了java一些基础类可以稳定的存在,不会被用户自定义类顶替掉。
双亲委派模型并不是完美的,在一些场景下会出现一些比较难解决的问题,举个例子,在使用SPI的时候,ServiceLoader是通过BootStrap类加载器加载的,在执行到加载用户编写的扩展类的时候,如果使用当前类的类加载器,是肯定无法加载到用户编写的类的,这个时候就无法继续执行了,所以这个时候就需要使用Thread的上下文类加载器,查看源码的时候我们就发现,在用户不主动传递ClassLoader的时候,会获取当前上下文类加载器,这样应用程序才能正常的执行。

public static <S> ServiceLoader<S> load(Class<S> service) {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    return ServiceLoader.load(service, cl);
}

转载请注明:学时网 » JAVA Launcher简析

喜欢 (2)or分享 (0)

您必须 登录 才能发表评论!