java launcher在哪_JAVA Launcher简析

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 ServiceLoader load(Class service) {

ClassLoader cl = Thread.currentThread().getContextClassLoader();

return ServiceLoader.load(service, cl);

}

喜欢 (0)or分享 (0)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值