zoukankan      html  css  js  c++  java
  • springboots04

    获取lib/下面的jar,并创建一个LaunchedURLClassLoader

    JarLauncher创建好Archive之后,通过getNestedArchives函数来获取到demo-0.0.1-SNAPSHOT.jar/lib下面的所有jar文件,并创建为List。

    注意上面提到,Archive都是有自己的URL的。

    获取到这些Archive的URL之后,也就获得了一个URL[]数组,用这个来构造一个自定义的ClassLoader:LaunchedURLClassLoader。

    创建好ClassLoader之后,再从MANIFEST.MF里读取到Start-Class,即com.example.SpringBootDemoApplication,然后创建一个新的线程来启动应用的Main函数。

        /**
         * Launch the application given the archive file and a fully configured classloader.
         */
        protected void launch(String[] args, String mainClass, ClassLoader classLoader)
                throws Exception {
            Runnable runner = createMainMethodRunner(mainClass, args, classLoader);
            Thread runnerThread = new Thread(runner);
            runnerThread.setContextClassLoader(classLoader);
            runnerThread.setName(Thread.currentThread().getName());
            runnerThread.start();
        }
    
        /**
         * Create the {@code MainMethodRunner} used to launch the application.
         */
        protected Runnable createMainMethodRunner(String mainClass, String[] args,
                ClassLoader classLoader) throws Exception {
            Class<?> runnerClass = classLoader.loadClass(RUNNER_CLASS);
            Constructor<?> constructor = runnerClass.getConstructor(String.class,
                    String[].class);
            return (Runnable) constructor.newInstance(mainClass, args);
        }
    • 1

    LaunchedURLClassLoader

    LaunchedURLClassLoader和普通的URLClassLoader的不同之处是,它提供了从Archive里加载.class的能力。

    结合Archive提供的getEntries函数,就可以获取到Archive里的Resource。当然里面的细节还是很多的,下面再描述。

    spring boot应用启动流程总结

    看到这里,可以总结下Spring Boot应用的启动流程:

    1. spring boot应用打包之后,生成一个fat jar,里面包含了应用依赖的jar包,还有Spring boot loader相关的类
    2. Fat jar的启动Main函数是JarLauncher,它负责创建一个LaunchedURLClassLoader来加载/lib下面的jar,并以一个新线程启动应用的Main函数。

    spring boot loader里的细节

    代码地址:https://github.com/spring-projects/spring-boot/tree/master/spring-boot-tools/spring-boot-loader

    JarFile URL的扩展

    Spring boot能做到以一个fat jar来启动,最重要的一点是它实现了jar in jar的加载方式。

    JDK原始的JarFile URL的定义可以参考这里:

    http://docs.oracle.com/javase/7/docs/api/java/net/JarURLConnection.html

    原始的JarFile URL是这样子的:

    jar:file:/tmp/target/demo-0.0.1-SNAPSHOT.jar!/

    jar包里的资源的URL:

    jar:file:/tmp/target/demo-0.0.1-SNAPSHOT.jar!/com/example/SpringBootDemoApplication.class

    可以看到对于Jar里的资源,定义以’!/’来分隔。原始的JarFile URL只支持一个’!/’。

    Spring boot扩展了这个协议,让它支持多个’!/’,就可以表示jar in jar,jar in directory的资源了。

    比如下面的URL表示demo-0.0.1-SNAPSHOT.jar这个jar里lib目录下面的spring-beans-4.2.3.RELEASE.jar里面的MANIFEST.MF:

    jar:file:/tmp/target/demo-0.0.1-SNAPSHOT.jar!/lib/spring-beans-4.2.3.RELEASE.jar!/META-INF/MANIFEST.MF

    自定义URLStreamHandler,扩展JarFile和JarURLConnection

    在构造一个URL时,可以传递一个Handler,而JDK自带有默认的Handler类,应用可以自己注册Handler来处理自定义的URL。

    public URL(String protocol,
               String host,
               int port,
               String file,
               URLStreamHandler handler)
        throws MalformedURLException

    参考: 
    https://docs.oracle.com/javase/8/docs/api/java/net/URL.html#URL-java.lang.String-java.lang.String-int-java.lang.String-

    Spring boot通过注册了一个自定义的Handler类来处理多重jar in jar的逻辑。

    这个Handler内部会用SoftReference来缓存所有打开过的JarFile。

    在处理像下面这样的URL时,会循环处理’!/’分隔符,从最上层出发,先构造出demo-0.0.1-SNAPSHOT.jar这个JarFile,再构造出spring-beans-4.2.3.RELEASE.jar这个JarFile,然后再构造出指向MANIFEST.MF的JarURLConnection。

    jar:file:/tmp/target/demo-0.0.1-SNAPSHOT.jar!/lib/spring-beans-4.2.3.RELEASE.jar!/META-INF/MANIFEST.MF
  • 相关阅读:
    【转】shell中的内建命令, 函数和外部命令
    clear out all variables without closing terminal
    linux中shell命令test用法和举例
    解决vim粘贴时格式混乱的问题
    scp的两种方式
    source 命令的用法,是在当前bash环境下执行脚本文件
    angularjs中下拉框select option默认值
    redux 及 相关插件 项目实战
    JavaScript 获取当前时间戳
    v-if v-else-if v-else
  • 原文地址:https://www.cnblogs.com/huaobin/p/14908787.html
Copyright © 2011-2022 走看看