服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - java -jar命令及SpringBoot通过java -jav启动项目的过程

java -jar命令及SpringBoot通过java -jav启动项目的过程

2023-05-16 01:02未知服务器之家 Java教程

目录 Pre 引导 新建工程 打包 启动 java -jar 干啥的 打包插件 spring-boot-maven-plugin简介 包结构 Archive的概念 JarFile JarLauncher工作流程 小结 本篇文章将为大家讲述关于 SpringBoot 项目工程完成后,是如何通过 java-jar 命令来启动的,以及介

目录
  • Pre
  • 引导
    • 新建工程 打包 启动
    • java -jar 干啥的
  • 打包插件
    • spring-boot-maven-plugin简介
    • 包结构
    • Archive的概念
    • JarFile
  • JarLauncher工作流程
    • 小结

      本篇文章将为大家讲述关于 SpringBoot 项目工程完成后,是如何通过 java-jar 命令来启动的,以及介绍 java-jar 命令的详细内容。希望本篇文章能够帮助到大家的学习!

      Pre

      大家开发的基于Spring Boot 的应用 ,jar形式, 发布的时候,绝大部分都是使用java -jar 启动。 得益于Spring Boot 的封装 , 再也不用操心搭建tomcat等相关web容器le , 一切变得非常美好, 那SpringBoot是怎么做到的呢?

      引导

      新建工程 打包 启动

      我们新创建一个Spring Boot的工程

      java -jar命令及SpringBoot通过java -jav启动项目的过程

      先打包一下

      java -jar命令及SpringBoot通过java -jav启动项目的过程

      执行以上命令之后,便生成了打包结果对应的两个文件。

      包结构

      下面针对文件的内容和结构进行一探究竟。

      spring-0.0.1-SNAPSHOT.jar
      ├── META-INF
      │   └── maven(主要是pom文件)
      │   └── MANIFEST.MF
      ├── BOOT-INF
      │   ├── classes
      │   │   └── 应用程序类
      │   └── lib
      │       └── 第三方依赖jar
      └── org
          └── springframework
              └── boot
                  └── loader
                      └── springboot启动程序

      META-INF内容

      Manifest-Version: 1.0
      Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
      Implementation-Title: spring
      Implementation-Version: 0.0.1-SNAPSHOT
      Spring-Boot-Layers-Index: BOOT-INF/layers.idx
      Start-Class: com.artisan.spring.Application
      Spring-Boot-Classes: BOOT-INF/classes/
      Spring-Boot-Lib: BOOT-INF/lib/
      Build-Jdk-Spec: 1.8
      Spring-Boot-Version: 2.4.1
      Created-By: Maven Jar Plugin 3.2.0
      Main-Class: org.springframework.boot.loader.JarLauncher

      Main-Class:org.springframework.boot.loader.JarLauncher ,这个是jar启动的Main函数Start-Class: com.artisan.spring.Application,这个是我们应用自己的Main函数

      Archive的概念

      在继续了解底层概念和原理之前,我们先来了解一下Archive的概念:

      • archive即归档文件,这个概念在linux下比较常见
      • 通常就是一个tar/zip格式的压缩包
      • jar是zip格式

      SpringBoot抽象了Archive的概念,一个Archive可以是jar(JarFileArchive),可以是一个文件目录(ExplodedArchive),可以抽象为统一访问资源的逻辑层

      关于Spring Boot中Archive的源码如下:

      public interface Archive extends Iterable<Archive.Entry> {
          // 获取该归档的url
          URL getUrl() throws MalformedURLException;
          // 获取jar!/META-INF/MANIFEST.MF或[ArchiveDir]/META-INF/MANIFEST.MF
          Manifest getManifest() throws IOException;
          // 获取jar!/BOOT-INF/lib/*.jar或[ArchiveDir]/BOOT-INF/lib/*.jar
          List<Archive> getNestedArchives(EntryFilter filter) throws IOException;
      }

      SpringBoot定义了一个接口用于描述资源,也就是org.springframework.boot.loader.archive.Archive

      java -jar命令及SpringBoot通过java -jav启动项目的过程

      其主入口新建了JarLauncher并调用父类Launcher中的launch方法启动程序。在创建JarLauncher时,父类ExecutableArchiveLauncher找到自己所在的jar,并创建archive。

      JarLauncher继承于org.springframework.boot.loader.ExecutableArchiveLauncher。该类的无参构造方法最主要的功能就是构建了当前main方法所在的FatJar的JarFileArchive对象。

      下面来看launch方法。该方法主要是做了2个事情:

      (1)以FatJar为file作为入参,构造JarFileArchive对象。获取其中所有的资源目标,取得其Url,将这些URL作为参数,构建了一个URLClassLoader

      (2)以第一步构建的ClassLoader加载MANIFEST.MF文件中Start-Class指向的业务类,并且执行静态方法main。进而启动整个程序。

      public abstract class ExecutableArchiveLauncher extends Launcher {
          private final Archive archive;
          public ExecutableArchiveLauncher() {
              try {
                  // 找到自己所在的jar,并创建Archive
                  this.archive = createArchive();
              }
              catch (Exception ex) {
                  throw new IllegalStateException(ex);
              }
          }
      }
      public abstract class Launcher {
          protected final Archive createArchive() throws Exception {
              ProtectionDomain protectionDomain = getClass().getProtectionDomain();
              CodeSource codeSource = protectionDomain.getCodeSource();
              URI location = (codeSource == null ? null : codeSource.getLocation().toURI());
              String path = (location == null ? null : location.getSchemeSpecificPart());
              if (path == null) {
                  throw new IllegalStateException("Unable to determine code source archive");
              }
              File root = new File(path);
              if (!root.exists()) {
                  throw new IllegalStateException(
                          "Unable to determine code source archive from " + root);
              }
              return (root.isDirectory() ? new ExplodedArchive(root)
                      : new JarFileArchive(root));
          }
      }

      在Launcher的launch方法中,通过以上archive的getNestedArchives方法找到/BOOT-INF/lib下所有jar及/BOOT-INF/classes目录所对应的archive,通过这些archives的url生成LaunchedURLClassLoader,并将其设置为线程上下文类加载器,启动应用。

      至此,才执行我们应用程序主入口类的main方法,所有应用程序类文件均可通过/BOOT-INF/classes加载,所有依赖的第三方jar均可通过/BOOT-INF/lib加载。

      小结

      • JarLauncher通过加载BOOT-INF/classes目录及BOOT-INF/lib目录下jar文件,实现了fat jar的启动。
      • SpringBoot通过扩展JarFile、JarURLConnection及URLStreamHandler,实现了jar in jar中资源的加载。
      • SpringBoot通过扩展URLClassLoader–LauncherURLClassLoader,实现了jar in jar中class文件的加载。
      • WarLauncher通过加载WEB-INF/classes目录及WEB-INF/lib和WEB-INF/lib-provided目录下的jar文件,实现了war文件的直接启动及web容器中的启动。

      通过spring-boot-plugin 生成了MANIFEST.MF , main-class 指定运行java -jar的主程序把依赖的jar文件 打包在fat jar.

      以上就是关于 java -jar命令的详细内容以及 SpringBoot 如何使用 java -jar命令来启动项目的具体过程。

      原文地址:https://blog.csdn.net/qq_36908872/article/details/127118772

      延伸 · 阅读

      精彩推荐