Springboot의 FatJar 및 Jar란 무엇입니까?

WBOY
풀어 주다: 2023-05-11 09:58:13
앞으로
1761명이 탐색했습니다.

    소개

    Spring Boot 애플리케이션은spring-boot-maven-plugin을 사용하여 빠르게 패키징하여spring-boot-maven-plugin快速打包,构建一个可执行jar。Spring Boot内嵌容器,通过java -jar命令便可以直接启动应用。

    虽然是一个简单的启动命令,背后却藏着很多知识。今天带着大家探索FAT JAR启动的背后原理。本文主要包含以下几个部分:

    • JAR 是什么。首先需要了解jar是什么,才知道java -jar做了什么事情。

    • FatJar 有什么不同。 Spring Boot提供的可执行jar与普通的jar有什么区别。

    • 启动时的类加载原理。 启动过程中类加载器做了什么?Spring Boot又如何通过自定义类加载器解决内嵌包的加载问题。

    • 启动的整个流程。最后整合前面三部分的内容,解析源码看如何完成启动。

    JAR 是什么

    JAR简介

    JAR文件(Java归档,英语:JavaARchive)是一种软件包文件格式,通常用于将大量的Java类文件、相关的元数据和资源(文本、图片等)文件聚合到一个文件,以便分发Java平台应用软件或库。简单点理解其实就是一个压缩包,既然是压缩包那么为了提取JAR文件的内容,可以使用任何标准的unzip解压缩软件提取内容。或者使用Java虚拟机自带命令jar -xf foo.jar来解压相应的jar文件。

    JAR 可以简单分为两类:

    • 非可执行JAR。打包时,不用指定main-class,也不可运行。普通jar包可以供其它项目进行依赖。

    • 可执行JAR。打jar包时,指定了main-class类,可以通过java -jar xxx.jar命令,执行main-classmain方法,运行jar包。可运行jar包不可被其他项目进行依赖。

    JAR结构

    包结构

    不管是非可行JAR还是可执行JAR解压后都包含两部分:META-INF目录(元数据)和package目录(编译后的class)。这种普通的jar不包含第三方依赖包,只包含应用自身的配置文件、class 等。

    . ├── META-INF │ ├── MANIFEST.MF #定义 └── org # 包路径(存放编译后的class) └── springframework
    로그인 후 복사
    描述文件MANIFEST.MF

    JAR包的配置文件是META-INF文件夹下的MANIFEST.MF文件。主要配置信息如下:

    • Manifest-Version: 用来定义manifest文件的版本,例如:Manifest-Version: 1.0

    • Created-By: 声明该文件的生成者,一般该属性是由jar命令行工具生成的,例如:Created-By: Apache Ant 1.5.1

    • Signature-Version: 定义jar文件的签名版本

    • Class-Path: 应用程序或者类装载器使用该值来构建内部的类搜索路径,可执行jar包里需要设置这个。

    上面是普通jar包的属性,可运行jar包的.MF文件中,还会有mian-classstart-class等属性。如果依赖了外部jar包,还会在MF文件中配置lib路径等信息。更多信息参见:maven为MANIFEST.MF文件添加内容的方法

    至于可运行jar包普通jar包的目录结构,没有什么特别固定的模式,总之,无论是什么结构,在.MF文件中,配置好jar包的信息,即可正常使用jar包了。

    FatJar有什么不同

    什么是FatJar?

    普通的jar只包含当前 jar的信息,不含有第三方 jar。当内部依赖第三方jar时,直接运行则会报错,这时候需要将第三方jar内嵌到可执行jar里。将一个jar及其依赖的三方jar全部打到一个包中,这个包即为 FatJar。

    SpringBoot FatJar解决方案

    Spring Boot为了解决内嵌jar问题,提供了一套FatJar解决方案,分别定义了jar目录结构MANIFEST.MF。在编译生成可执行 jar 的基础上,使用spring-boot-maven-plugin按Spring Boot 的可执行包标准repackage실행 가능한 jar을 빌드할 수 있습니다. Spring Boot에는 컨테이너가 내장되어 있으며java -jar명령을 통해 애플리케이션을 직접 시작할 수 있습니다.

    간단한 시작 명령이지만 그 뒤에는 많은 지식이 숨겨져 있습니다. 오늘은
    FAT JAR
    의 시작 뒤에 숨은 원칙을 알아보도록 하겠습니다. 이 기사는 주로 다음 부분을 포함하고 있습니다:

    • JAR이란 무엇입니까. 먼저,java -jar가 무엇을 하는지 알기 전에 jar가 무엇인지 이해해야 합니다.
    • FatJar의 차이점은 무엇인가요? Spring Boot에서 제공하는 실행 가능한 jar과 일반 jar의 차이점은 무엇입니까?
    • 시작 시 클래스 로딩 원칙. 시작하는 동안 클래스로더는 무엇을 합니까? Spring Boot는 사용자 정의 클래스 로더를 통해 임베디드 패키지의 로딩 문제를 어떻게 해결합니까?
    • 입문의 전체 과정. 마지막으로 앞선 세 부분의 내용을 통합하고 소스코드를 분석해 스타트업을 완성하는 방법을 살펴본다.
    • JAR이란 무엇입니까

      JAR 소개

      JAR 파일(Java Archive, 영어: Java ARchive)은 소프트웨어 패키지 파일 형식으로, 일반적으로 대용량 다수의 Java 클래스 파일, 관련 메타데이터 및 리소스(텍스트, 이미지 등) 파일을 하나의 파일로 모아 Java 플랫폼 응용 소프트웨어 또는 라이브러리를 배포합니다. 간단히 이해하면 실제로는 압축된 패키지이므로 JAR 파일의 내용을 추출하려면 표준 압축 풀기 소프트웨어를 사용하여 내용을 추출할 수 있습니다. 또는 Java 가상 머신과 함께 제공되는 jar -xf foo.jar명령을 사용하여 해당 jar 파일의 압축을 해제하세요. JAR은 간단히 두 가지 범주로 나눌 수 있습니다:
      • 실행할 수 없는 JAR. 패키징 시main-class를 지정할 필요가 없으며 실행할 수 없습니다. 일반 jar 패키지는 다른 프로젝트에서 의존하는 데 사용될 수 있습니다.
      • 실행 가능한 JAR. jar 패키지를 빌드할 때main-class클래스가 지정됩니다.java -jar xxx.jar명령을 사용하여main-class를 실행할 수 있습니다. code> >main메소드는 jar 패키지를 실행합니다. 실행 가능한 jar 패키지 는 다른 프로젝트에 의존할 수 없습니다.
      • JAR 구조

        패키지 구조실행 불가능한 JAR이든 실행 가능한 JAR이든 압축 해제 후 두 부분으로 구성됩니다: META-INF디렉터리(메타데이터) 및 package디렉터리(컴파일된 클래스). 이 일반 jar에는 타사 종속성 패키지가 포함되지 않고 애플리케이션 자체 구성 파일, 클래스 등만 포함됩니다.
           org.springframework.boot spring-boot-maven-plugin   
        로그인 후 복사
        로그인 후 복사
        설명 파일 MANIFEST.MFJAR 패키지 구성 파일은 META-INF폴더 하위의 MANIFEST.MF파일입니다. 주요 구성 정보는 다음과 같습니다.
        • Manifest-Version: 매니페스트 파일의 버전을 정의하는 데 사용됩니다. 예: Manifest-Version: 1.0
        • Created-By: 파일 생성기를 선언합니다. 일반적으로 이 속성은 jar 명령줄 도구에 의해 생성됩니다. 예: Created-By: Apache Ant 1.5.1
        • < li>Signature-Version: jar 파일의 정의 서명된 버전
        • Class-Path: 애플리케이션 또는 클래스 로더는 이 값을 사용하여 내부 클래스 검색 경로를 구축합니다. 실행 가능한 jar 패키지.
        • 위는 일반 jar 패키지의 속성입니다. runnable jar 패키지의 .MF 파일에는 mian-class또는 start도 있습니다. -class< /code> 및 기타 속성. 외부 jar 패키지를 사용하는 경우 lib 경로 및 기타 정보도 MF 파일에 구성됩니다. 자세한 내용은참조: maven이 MANIFEST.MF 파일에 콘텐츠를 추가하는 방법 runnable jar 패키지 및 일반 jar 패키지의 디렉터리 구조에는 특별히 고정된 패턴이 없습니다. 구조에 관계없이 .MF 파일에 jar 패키지 정보를 설정하면 jar 패키지를 정상적으로 사용할 수 있습니다. FatJar의 차이점은 무엇인가요?

          FatJar가 무엇인가요?

          일반 jar에는 현재 jar에 대한 정보만 포함되며 타사 jar는 포함되지 않습니다. 내부적으로 타사 jar를 사용하는 경우 직접 실행하면 오류가 보고됩니다. 이 경우 타사 jar를 실행 가능한 jar에 포함해야 합니다. 병과 이에 종속된 타사 항아리를 하나의 패키지에 담는 것이 FatJar입니다.

          SpringBoot FatJar 솔루션

          Spring Boot는 jar 디렉터리 구조 및 MANIFEST를 각각 정의하는 내장된 jar 문제를 해결하기 위한 FatJar 솔루션 세트를 제공합니다. .MF. 실행 가능한 jar를 컴파일하고 생성한 후, Spring Boot의 실행 가능 패키지 표준 repackage에 따라 spring-boot-maven-plugin을 사용하여 실행 가능한 Spring Boot jar를 얻습니다. 실행 가능한 Jar의 종류에 따라 실행 가능한 Jar와 실행 가능한 War의 두 가지 유형으로 나뉩니다. spring-boot-maven-plugin 패키징 과정새로 생성된 빈 SpringBoot 프로젝트 어디에도 관련 클래스에 대한 명시적인 소개나 작성이 없기 때문입니다. 실제로 새로 생성된 각 SpringBoot 프로젝트에 대해 pom.xml 파일에서 다음 플러그인을 볼 수 있습니다.
             org.springframework.boot spring-boot-maven-plugin   
          로그인 후 복사
          로그인 후 복사

          这个是SpringBoot官方提供的用于打包FatJar的插件,org.springframework.boot.loader下的类其实就是通过这个插件打进去的;

          下面是此插件将 loader 相关类打入 FatJar 的一个执行流程:

          org.springframework.boot.maven#execute-> org.springframework.boot.maven#repackage -> org.springframework.boot.loader.tools.Repackager#repackage-> org.springframework.boot.loader.tools.Repackager#writeLoaderClasses-> org.springframework.boot.loader.tools.JarWriter#writeLoaderClasses
          로그인 후 복사

          最终的执行方法就是下面这个方法,通过注释可以看出,该方法的作用就是将 spring-boot-loader 的classes 写入到 FatJar 中。

          /** * Write the required spring-boot-loader classes to the JAR. * @throws IOException if the classes cannot be written */ @Override public void writeLoaderClasses() throws IOException { writeLoaderClasses(NESTED_LOADER_JAR); }
          로그인 후 복사
          打包结果

          Spring Boot项目被编译以后,在targert目录下存在两个jar文件:一个是xxx.jarxxx.jar.original

          • 其中xxx.jar.original是maven编译后的原始jar文件,即标准的java jar。该文件仅包含应用本地资源。 如果单纯使用这个jar,无法正常运行,因为缺少依赖的第三方资源。

          • 因此spring-boot-maven-plugin插件对这个xxx.jar.original再做一层加工,引入第三方依赖的jar包等资源,将其"repackage"xxx.jar。可执行Jar的文件结构如下图所示:

          . ├── BOOT-INF │ ├── classes │ │ ├── application.properties # 用户-配置文件 │ │ └── com │ │ └── glmapper │ │ └── bridge │ │ └── boot │ │ └── BootStrap.class # 用户-启动类 │ └── lib │ ├── jakarta.annotation-api-1.3.5.jar │ ├── jul-to-slf4j-1.7.28.jar │ ├── log4j-xxx.jar # 表示 log4j 相关的依赖简写 ├── META-INF │ ├── MANIFEST.MF │ └── maven │ └── com.glmapper.bridge.boot │ └── guides-for-jarlaunch │ ├── pom.properties │ └── pom.xml └── org └── springframework └── boot └── loader ├── ExecutableArchiveLauncher.class ├── JarLauncher.class ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class ├── LaunchedURLClassLoader.class ├── Launcher.class ├── MainMethodRunner.class ├── PropertiesLauncher$1.class ├── PropertiesLauncher$ArchiveEntryFilter.class ├── PropertiesLauncher$PrefixMatchingArchiveFilter.class ├── PropertiesLauncher.class ├── WarLauncher.class ├── archive │ ├── # 省略 ├── data │ ├── # 省略 ├── jar │ ├── # 省略 └── util └── SystemPropertyUtils.class
          로그인 후 복사
          • META-INF:存放元数据。MANIFEST.MF 是 jar 规范,Spring Boot 为了便于加载第三方 jar 对内容做了修改;

          • org:存放Spring Boot 相关类,比如启动时所需的 Launcher 等;

          • BOOT-INF/class:存放应用编译后的 class 文件;

          • BOOT-INF/lib:存放应用依赖的 JAR 包。

          Spring Boot的MANIFEST.MF和普通jar有些不同:

          Spring-Boot-Version: 2.1.3.RELEASE Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.rock.springbootlearn.SpringbootLearnApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Build-Jdk: 1.8.0_131
          로그인 후 복사

          Main-Class:java -jar启动引导类,但这里不是项目中的类,而是Spring Boot内部的JarLauncher
          Start-Class:这个才是正在要执行的应用内部主类

          所以java -jar启动的时候,加载运行的是JarLauncher。Spring Boot内部如何通过JarLauncher 加载Start-Class 执行呢?为了更清楚加载流程,我们先介绍下java -jar是如何完成类加载逻辑的。

          启动时的类加载原理

          这里简单说下java -jar启动时是如何完成记载类加载的。Java 采用了双亲委派机制,Java语言系统自带有三个类加载器:

          • Bootstrap CLassloder:最顶层的加载类,主要加载核心类库

          • Extention ClassLoader:扩展的类加载器,加载目录%JRE_HOME%/lib/ext目录下的jar包和class文件。 还可以加载-D java.ext.dirs选项指定的目录。

          • AppClassLoader:是应用加载器。

          默认情况下通过java -classpathjava -cpjava -jar使用的类加载器都是AppClassLoader。 普通可执行jar通过java -jar启动后,使用AppClassLoader加载Main-class类。 如果第三方jar不在AppClassLoader里,会导致启动时候会报ClassNotFoundException。

          例如在Spring Boot可执行jar的解压目录下,执行应用的主函数,就直接报该错误:

          Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication
          at com.glmapper.bridge.boot.BootStrap.main(BootStrap.java:13)
          Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
          at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
          at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
          ... 1 more

          从异常堆栈来看,是因为找不到SpringApplication这个类;这里其实还是比较好理解的,BootStrap类中引入了SpringApplication,但是这个类是在BOOT-INF/lib下的,而java指令在启动时未指明classpath,依赖的第三方jar无法被加载。

          Spring BootJarLauncher启动时,会将所有依赖的内嵌 jar (BOOT-INF/lib 目录下) 和class(BOOT-INF/classes 目录)都加入到自定义的类加载器LaunchedURLClassLoader中,并用这个ClassLoder去加载MANIFEST.MF配置Start-Class,则不会出现类找不到的错误。

          LaunchedURLClassLoader是URLClassLoader的子类, URLClassLoader会通过URL[] 来搜索类所在的位置。Spring Boot 则将所需要的内嵌文档组装成URL[],最终构建LaunchedURLClassLoader类。

          启动的整个流程

          有了以上知识的铺垫,我们看下整个 FatJar 启动的过程会是怎样。为了以便查看源码和远程调试,可以在 pom.xml 引入下面的配置:

           org.springframework.boot spring-boot-loader 
          로그인 후 복사

          简单概括起来可以分为几步:

          • java -jar 启动,AppClassLoader 则会加载 MANIFEST.MF 配置的Main-Class, JarLauncher。

          • JarLauncher启动时,注册URL关联协议。

          • 获取所有内嵌的存档(内嵌jar和class)

          • 根据存档的URL[]构建类加载器。

          • 然后用这个类加载器加载Start-Class。 保证这些类都在同一个ClassLoader中。

          위 내용은 Springboot의 FatJar 및 Jar란 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    관련 라벨:
    원천:yisu.com
    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    최신 이슈
    최신 다운로드
    더>
    웹 효과
    웹사이트 소스 코드
    웹사이트 자료
    프론트엔드 템플릿
    회사 소개 부인 성명 Sitemap
    PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!