Pandora Bootstrap源码分析

@SpringBootApplication
public class HSFProviderApplication {

    public static void main(String[] args) {
        // 启动 Pandora Boot 用于加载 Pandora 容器
        PandoraBootstrap.run(args);
        SpringApplication.run(HSFProviderApplication.class, args);
        // 标记服务启动完成,并设置线程 wait。防止用户业务代码运行完毕退出后,导致容器退出。
        PandoraBootstrap.markStartupAndWait();
    }
}
就这么一个简单的代码,都可以实现classloder的隔离,为什么这么神奇呢?

在我的认知里,是没有办法改变当前的classloder的,当前的 SpringApplication.run的时候,肯定是系统的classloder啊,就让我们来揭开迷雾吧。

PandoraBootstrap.run的时候,调用的核心方法:

参数mainClass就是HSFProviderApplication这个有main方法的入口类
参数args就是main方法的参数
参数的classLoader是我们自己创建的classloader

 public static void reLaunch(String[] args, String mainClass, ClassLoader classLoader) {
        IsolatedThreadGroup threadGroup = new IsolatedThreadGroup(mainClass);
        Thread launchThread = new Thread(threadGroup, new LaunchRunner(mainClass, args), "main");
        launchThread.setContextClassLoader(classLoader);
        launchThread.start();
        LaunchRunner.join(threadGroup); //main方法执行的线程会一直阻塞在这里
        threadGroup.rethrowUncaughtException();
    }
可以看到是创建了一个新的线程,这个线程做的事情很简单,就是用传入的classloader,执行我们的main方法
public void run() {
            ...
            Class<?> startClass = classLoader.loadClass(this.startClassName);
            Method mainMethod = startClass.getMethod("main", String[].class);
            if (!mainMethod.isAccessible()) {
                mainMethod.setAccessible(true);
            }

            mainMethod.invoke((Object)null, this.args)
这样就做到了偷天换日,最开始的main方法的线程是阻塞在那里的,并没有继续往下走,然后Pandora Bootstrap启动了一个新的线程,用新创建的classloder来执行main方法。

由于我们创建的classloder是系统classloder的子类,我们就可以做文章了,中间件的类用新创建的classloder来加载,业务的类用系统的classloder来加载。是不是非常巧妙啊。

也就是说,第一行代码PandoraBootstrap.run(args)是执行了两遍.

如何保证不会执行多次加载逻辑,甚至死循环的呢?第一遍是系统的classloder,第二遍虽然看上去是我们自己创建的classloder,但我们我们创建的classloder是委托给系统的classloder的,所以其实还是相同的classloder。这就很简单了,PandoraBootstrap执行第一遍之后就改一个bool变量,第二遍读到这个变量改了就直接跳过了。

  if (SarLoaderUtils.unneedLoadSar()) {
            LogConfigUtil.initLoggingSystem();
        } else {
            URL[] urls = ClassLoaderUtils.getUrls(PandoraBootstrap.class.getClassLoader());
            if (urls == null) {
                throw new IllegalStateException("Can not find urls from the ClassLoader of PandoraBootstrap. ClassLoader: " + PandoraBootstrap.class.getClassLoader());
            } else {
                urls = AutoConfigWrapper.autoConfig(urls);
                ReLaunchMainLauncher.launch(args, deduceMainApplicationClass().getName(), urls);
            }
        }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,147评论 0 62
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,394评论 11 349
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,436评论 0 4
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,877评论 0 10
  • 2016年,生命中又一个365天即将过去,感叹岁月悠悠、时间飞逝,我们无法挽留,但仍需总结与反思并给予展望。...
    小琳公子阅读 235评论 0 0