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);
            }
        }

猜你喜欢

转载自blog.csdn.net/weixin_34313182/article/details/87387301
今日推荐