Table of Contents
Introduction
What is JAR
Introduction to JAR
打包结果
启动时的类加载原理
启动的整个流程
Home Java javaTutorial What are FatJar and Jar in Springboot?

What are FatJar and Jar in Springboot?

May 11, 2023 am 09:58 AM
jar springboot fatjar

    Introduction

    Spring Boot applications can be quickly packaged using spring-boot-maven-plugin to build an executable jar. Spring Boot has an embedded container, and the application can be started directly through the java -jar command.

    Although it is a simple startup command, there is a lot of knowledge hidden behind it. Today I will take you to explore the principles behind FAT JAR startup. This article mainly contains the following parts:

    • What is JAR. First, you need to understand what jar is before you know what java -jar does.

    • What's the difference with FatJar. What is the difference between the executable jar provided by Spring Boot and the ordinary jar?

    • Class loading principle at startup. What does the classloader do during startup? How does Spring Boot solve the loading problem of embedded packages through a custom class loader.

    • The entire process started. Finally, integrate the contents of the previous three parts and analyze the source code to see how to complete the startup.

    What is JAR

    Introduction to JAR

    JAR file (Java Archive, English: Java ARchive) is a software package file format that is usually used to aggregate a large number of Java class files, related metadata and resource (text, images, etc.) files into one file to distribute Java platform application software or libraries. To understand it simply, it is actually a compressed package. Since it is a compressed package, in order to extract the contents of the JAR file, you can use any standard unzip decompression software to extract the contents. Or use the command jar -xf foo.jar that comes with the Java virtual machine to decompress the corresponding jar file.

    JARs can be simply divided into two categories:

    • Non-executable JAR. When packaging, you do not need to specify main-class, and it cannot be run. Ordinary jar packages can be used by other projects to depend on.

    • Executable JAR. When building a jar package, the main-class class is specified. You can execute the main# of main-class through the java -jar xxx.jar command. ##Method, run the jar package. The runnable jar package cannot be depended on by other projects.

    JAR structure

    Package structure
    Whether it is a non-viable JAR or an executable JAR, it contains two parts after decompression:

    META-INF directory (metadata) and package directory (compiled class). This ordinary jar does not contain third-party dependency packages, but only the application's own configuration files, classes, etc.

    .
    ├── META-INF
    │   ├── MANIFEST.MF  #定义
    └── org  # 包路径(存放编译后的class)
        └── springframework
    Copy after login

    Description file MANIFEST.MF
    The configuration file of the JAR package is the

    MANIFEST.MF file in the META-INF folder. The main configuration information is as follows:

    • Manifest-Version: used to define the version of the manifest file, for example: Manifest-Version: 1.0

    • Created-By: Declare the generator of the file. Generally, this attribute is generated by the jar command line tool, for example: Created-By: Apache Ant 1.5.1

    • Signature-Version: Define the signature version of the jar file

    • Class-Path: The application or class loader uses this value to build the internal class search path, which needs to be set in the executable jar package this.

    The above are the attributes of

    normal jar package, the .MF file of runnable jar package, there will also be mian- Attributes such as class or start-class. If you rely on an external jar package, the lib path and other information will also be configured in the MF file. More informationSee: How to add content to the MANIFEST.MF file with maven

    As for the directories of

    runnable jar packages and normal jar packages There is no particularly fixed pattern for the structure. In short, no matter what the structure is, after configuring the jar package information in the .MF file, you can use the jar package normally.

    What is the difference between FatJar

    What is FatJar?

    Ordinary jar only contains information about the current jar and does not contain third-party jars. When internally relying on a third-party jar, an error will be reported if run directly. In this case, the third-party jar needs to be embedded into the executable jar.

    Put a jar and its dependent third-party jars into one package. This package is FatJar.

    SpringBoot FatJar solution

    Spring BootIn order to solve the problem of embedded jars, a set of FatJar solutions are provided, which define jar directories respectively. Structure and MANIFEST.MF. On the basis of compiling and generating the executable jar, use spring-boot-maven-plugin according to the Spring Boot executable package standard repackage to obtain the executable Spring Boot jar. According to the type of executable jar, it is divided into two types: executable Jar and executable war.

    spring-boot-maven-plugin packaging process
    Because there is no explicit introduction or writing of related classes anywhere in the newly created empty SpringBoot project. In fact, for each newly created SpringBoot project, you can see the following plug-in in its pom.xml file:

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    Copy after login

    这个是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
    Copy after login

    最终的执行方法就是下面这个方法,通过注释可以看出,该方法的作用就是将 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);
    }
    Copy after login
    打包结果

    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
    Copy after login
    • 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
    Copy after login

    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 Boot JarLauncher启动时,会将所有依赖的内嵌 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 引入下面的配置:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-loader</artifactId>
    </dependency>
    Copy after login

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

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

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

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

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

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

    The above is the detailed content of What are FatJar and Jar in Springboot?. For more information, please follow other related articles on the PHP Chinese website!

    Statement of this Website
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

    Hot AI Tools

    Undresser.AI Undress

    Undresser.AI Undress

    AI-powered app for creating realistic nude photos

    AI Clothes Remover

    AI Clothes Remover

    Online AI tool for removing clothes from photos.

    Undress AI Tool

    Undress AI Tool

    Undress images for free

    Clothoff.io

    Clothoff.io

    AI clothes remover

    AI Hentai Generator

    AI Hentai Generator

    Generate AI Hentai for free.

    Hot Article

    R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
    2 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
    Repo: How To Revive Teammates
    4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
    Hello Kitty Island Adventure: How To Get Giant Seeds
    4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

    Hot Tools

    Notepad++7.3.1

    Notepad++7.3.1

    Easy-to-use and free code editor

    SublimeText3 Chinese version

    SublimeText3 Chinese version

    Chinese version, very easy to use

    Zend Studio 13.0.1

    Zend Studio 13.0.1

    Powerful PHP integrated development environment

    Dreamweaver CS6

    Dreamweaver CS6

    Visual web development tools

    SublimeText3 Mac version

    SublimeText3 Mac version

    God-level code editing software (SublimeText3)

    How Springboot integrates Jasypt to implement configuration file encryption How Springboot integrates Jasypt to implement configuration file encryption Jun 01, 2023 am 08:55 AM

    Introduction to Jasypt Jasypt is a java library that allows a developer to add basic encryption functionality to his/her project with minimal effort and does not require a deep understanding of how encryption works. High security for one-way and two-way encryption. , standards-based encryption technology. Encrypt passwords, text, numbers, binaries... Suitable for integration into Spring-based applications, open API, for use with any JCE provider... Add the following dependency: com.github.ulisesbocchiojasypt-spring-boot-starter2. 1.1Jasypt benefits protect our system security. Even if the code is leaked, the data source can be guaranteed.

    How to run jar files in Linux How to run jar files in Linux Feb 20, 2024 am 10:40 AM

    Prerequisites for running JAR files Running JAR files on a Linux system requires the installation of the Java Runtime Environment (JRE), which is the basic component required to execute Java applications, including the Java Virtual Machine (JVM), core class libraries, etc. Many mainstream Linux distributions, such as Ubuntu, Debian, Fedora, openSUSE, etc., provide software libraries of JRE packages to facilitate user installation. The following article will detail the steps to install JRE on popular distributions. After setting up the JRE, you can choose to use the command line terminal or the graphical user interface to start the JAR file according to your personal preference. Your choice may depend on familiarity with Linux shells and personal preference

    How to use Redis to implement distributed locks in SpringBoot How to use Redis to implement distributed locks in SpringBoot Jun 03, 2023 am 08:16 AM

    1. Redis implements distributed lock principle and why distributed locks are needed. Before talking about distributed locks, it is necessary to explain why distributed locks are needed. The opposite of distributed locks is stand-alone locks. When we write multi-threaded programs, we avoid data problems caused by operating a shared variable at the same time. We usually use a lock to mutually exclude the shared variables to ensure the correctness of the shared variables. Its scope of use is in the same process. If there are multiple processes that need to operate a shared resource at the same time, how can they be mutually exclusive? Today's business applications are usually microservice architecture, which also means that one application will deploy multiple processes. If multiple processes need to modify the same row of records in MySQL, in order to avoid dirty data caused by out-of-order operations, distribution needs to be introduced at this time. The style is locked. Want to achieve points

    How SpringBoot integrates Redisson to implement delay queue How SpringBoot integrates Redisson to implement delay queue May 30, 2023 pm 02:40 PM

    Usage scenario 1. The order was placed successfully but the payment was not made within 30 minutes. The payment timed out and the order was automatically canceled. 2. The order was signed and no evaluation was conducted for 7 days after signing. If the order times out and is not evaluated, the system defaults to a positive rating. 3. The order is placed successfully. If the merchant does not receive the order for 5 minutes, the order is cancelled. 4. The delivery times out, and push SMS reminder... For scenarios with long delays and low real-time performance, we can Use task scheduling to perform regular polling processing. For example: xxl-job Today we will pick

    How to solve the problem that springboot cannot access the file after reading it into a jar package How to solve the problem that springboot cannot access the file after reading it into a jar package Jun 03, 2023 pm 04:38 PM

    Springboot reads the file, but cannot access the latest development after packaging it into a jar package. There is a situation where springboot cannot read the file after packaging it into a jar package. The reason is that after packaging, the virtual path of the file is invalid and can only be accessed through the stream. Read. The file is under resources publicvoidtest(){Listnames=newArrayList();InputStreamReaderread=null;try{ClassPathResourceresource=newClassPathResource("name.txt");Input

    Comparison and difference analysis between SpringBoot and SpringMVC Comparison and difference analysis between SpringBoot and SpringMVC Dec 29, 2023 am 11:02 AM

    SpringBoot and SpringMVC are both commonly used frameworks in Java development, but there are some obvious differences between them. This article will explore the features and uses of these two frameworks and compare their differences. First, let's learn about SpringBoot. SpringBoot was developed by the Pivotal team to simplify the creation and deployment of applications based on the Spring framework. It provides a fast, lightweight way to build stand-alone, executable

    How SpringBoot customizes Redis to implement cache serialization How SpringBoot customizes Redis to implement cache serialization Jun 03, 2023 am 11:32 AM

    1. Customize RedisTemplate1.1, RedisAPI default serialization mechanism. The API-based Redis cache implementation uses the RedisTemplate template for data caching operations. Here, open the RedisTemplate class and view the source code information of the class. publicclassRedisTemplateextendsRedisAccessorimplementsRedisOperations, BeanClassLoaderAware{//Declare key, Various serialization methods of value, the initial value is empty @NullableprivateRedisSe

    How to implement Springboot+Mybatis-plus without using SQL statements to add multiple tables How to implement Springboot+Mybatis-plus without using SQL statements to add multiple tables Jun 02, 2023 am 11:07 AM

    When Springboot+Mybatis-plus does not use SQL statements to perform multi-table adding operations, the problems I encountered are decomposed by simulating thinking in the test environment: Create a BrandDTO object with parameters to simulate passing parameters to the background. We all know that it is extremely difficult to perform multi-table operations in Mybatis-plus. If you do not use tools such as Mybatis-plus-join, you can only configure the corresponding Mapper.xml file and configure The smelly and long ResultMap, and then write the corresponding sql statement. Although this method seems cumbersome, it is highly flexible and allows us to

    See all articles