Incremental Updates of JAR Files via Command Line on Linux/Windows Servers

Excluding traditional WAR package deployment, and focusing on the currently commonly used JAR packages, there are roughly three scenarios for updating services on the server:

  • Scenario 1: Incremental updates of certain class files in the JAR package.
  • Scenario 2: Executable JAR packages and lib dependency packages are packaged separately, requiring incremental upgrades of certain lib dependency packages.
  • Scenario 3: Updating dependency JARs in a fat JAR package or class files in the JAR package (Spring Boot defaults to packaging a fat JAR, which bundles all dependencies and source packages into one JAR). When only a small amount of code has changed, updating the service is very unfriendly, as a full update requires transferring a very large JAR package.

Now, let’s take examples of how to use the command line to update for these three scenarios. Please ensure that the Java environment variables are configured on the server or locally, and that the <span>jar</span> command can be found normally.

Scenario 1

Incremental updates of certain class files in the JAR package.

Extract the <span>filetype.properties</span> configuration file from the JAR package, modify the configuration information, and then update it back; for incremental updates of the <span>top/wys/utils/ClassUtils.class</span> file, you can first use the <span>vim</span> command to check the file path in the JAR package before extraction.

Start Extraction

# Only extract the required files, no need to extract the entire JAR jar xvf ZmlTools-1.4.2.jar top/wys/utils/ClassUtils.class filetype.properties

Command Breakdown

Let’s break down this command into several parts:

  1. <span>jar</span>: This is the name of the command, representing the Java Archive Tool. It is used to create and manage <span>.jar</span> files. JAR files are essentially ZIP format compressed files used to package Java class files, metadata, and resources (such as images, configuration files, etc.).

  2. <span>xvf</span>: This is a set of options passed to the <span>jar</span> command, which together define the operation to be performed. The order of the options is usually not important, but they must follow the <span>jar</span> command.

  • <span>x</span>: Represents “extract”. This is the main operation to be performed by the command, which is to extract files from the archive.
  • <span>v</span>: Represents “verbose”. Using this option will display detailed operations in standard output (usually your terminal), such as which files are being extracted, their names, and sizes.
  • <span>f</span>: Represents “file”. This option tells the <span>jar</span> command that the name of the archive file to be operated on is specified on the command line (in this case, <span>ZmlTools-1.4.2.jar</span>). If the <span>f</span> option is not used, the <span>jar</span> command will attempt to read the archive content from standard input.
  • <span>ZmlTools-1.4.2.jar</span>: This is the name of the target JAR file to perform the extraction operation.

  • <span>top/wys/utils/ClassUtils.class</span> and <span>filetype.properties</span>: These are two space-separated file path parameters. They specify the specific files to be extracted from the <span>ZmlTools-1.4.2.jar</span> file.

    • <span>jar</span> command allows you to specify one or more files for extraction.
    • If no files are specified here, the <span>jar</span> command will default to extracting all files in the JAR package.

    Command Execution Process

    When you execute this command in the terminal, the following occurs:

    1. <span>jar</span> tool will open the archive file named <span>ZmlTools-1.4.2.jar</span>.
    2. It will look for the files <span>top/wys/utils/ClassUtils.class</span> and <span>filetype.properties</span> in the archive file.
    3. Once the files are found, the <span>jar</span> tool will extract and copy them to your current directory.
    4. For files with paths (like <span>top/wys/utils/ClassUtils.class</span>), the <span>jar</span> command will create the corresponding folder structure in the current directory (i.e., <span>top/wys/utils/</span>), and then place the <span>ClassUtils.class</span> file inside it.
    5. Since the <span>v</span> option was used, during the extraction process, the terminal will print out information similar to the following, informing you of the detailed progress of the operation:
      created: top/created: top/wys/created: top/wys/utils/inflated: top/wys/utils/ClassUtils.classinflated: filetype.properties
  • After the operation is completed, the original <span>ZmlTools-1.4.2.jar</span> file remains unchanged.
  • Sample Screenshot

    This is an operation screenshot under Windows, which can be operated directly on the server without downloading the JAR package to the local machine.

    image.png

    Start Compressing Updates

    After modifications are completed, compress the files back into the JAR package.

    jar uvf ZmlTools-1.4.2.jar top/wys/utils/ClassUtils.class filetype.properties
    image.png

    Command Breakdown

    Let’s break down each part of the command:

    1. <span>jar</span>: This is still the command for the Java Archive Tool.

    2. <span>uvf</span>: This is a set of options passed to the <span>jar</span> command. The key here is <span>u</span>.

    • <span>u</span>: Represents “update”. This is the main operation to be performed by this command. It will add new files to the specified archive file or replace existing files with the same name in the archive.
    • <span>v</span>: Represents “verbose”. Using this option will display detailed operations in the terminal, such as “adding: top/wys/utils/ClassUtils.class”, allowing you to clearly see which files have been added or updated.
    • <span>f</span>: Represents “file”. This option tells the <span>jar</span> command that the name of the archive file to be operated on is specified on the command line (i.e., <span>ZmlTools-1.4.2.jar</span>).
  • <span>ZmlTools-1.4.2.jar</span>: This is the name of the target JAR file that is being updated. This file must already exist.

  • <span>top/wys/utils/ClassUtils.class</span> and <span>filetype.properties</span>: These two parameters specify the source files used for the update. These files must exist in your current directory when executing the command.

  • Command Execution Process

    When you execute this command, the following occurs:

    1. <span>jar</span> tool will open the archive file named <span>ZmlTools-1.4.2.jar</span> for modification.
    2. It will look for the source files <span>top/wys/utils/ClassUtils.class</span> and <span>filetype.properties</span> in your current local file system.
    • Important Note:<span>jar</span> tool expects to find a folder named <span>top</span> in the current directory, which contains a <span>wys</span> folder, which in turn contains a <span>utils</span> folder, ultimately containing the <span>ClassUtils.class</span> file. It also expects to find the <span>filetype.properties</span> file in the current directory.
  • For each specified source file, the <span>jar</span> tool will perform the following checks:
    • If the local source file is updated (timestamp is later), the <span>jar</span> tool will replace the old file in the JAR package with the local file.
    • If the local source file is not updated (timestamp is the same or earlier), the <span>jar</span> tool will skip this file and perform no operation.
    • If a file with the same name does not exist in the JAR package: The <span>jar</span> tool will directly add this new file to the JAR package while maintaining its directory structure.
    • If a file with the same name already exists in the JAR package: The <span>jar</span> tool will compare the modification timestamps of the local source file and the file in the JAR package.
  • This update operation is performed directly on the original <span>ZmlTools-1.4.2.jar</span> file, modifying this file.
  • Since the <span>v</span> option was used, during the update process, the terminal will print a list of files that were added or replaced.
  • Core Differences

    Command <span>jar xvf ...</span> <span>jar uvf ...</span>
    Operation Extract Update
    Data Flow From JAR package -> To local file system From local file system -> To JAR package
    Impact on JAR package No modification to the original JAR package Direct modification of the original JAR package

    Scenario 2

    Packaging method uses a separation of dependency lib packages and executable source JAR packages.

    Tomcat has a vulnerability, and its dependencies need to be upgraded.

    1. Copy the upgraded JAR packages

    1. Copy the three Tomcat JAR packages from the lib directory to the corresponding service lib directory, back up the original lower version JAR packages, and then delete them.

      # Enter the lib directory and back up tar -zcvf tomcat-20240416-bak.tar.gz tomcat-*.jar # Move the backup file to the parent directory mv tomcat-20240416-bak.tar.gz ../ # Remove lower version JAR packages rm -rf tomcat-*.jar # Manually place the higher version JAR packages
    image.png

    2. Modify the version number of the dependent JAR packages

    Update the version number of Tomcat in the original running JAR package’s <span>MANIFEST.MF</span> file to <span>9.0.87</span>

    Taking flowCharge as an example:

    1. Extract the MANIFEST.MF file from the JAR package.
    # jar xvf xxx.jar META-INF/MANIFEST.MF extracts the MANIFEST.MF file from the META-INF directory of xxx.jar to the current directory, maintaining the extracted file directory as META-INF/MANIFEST.MF jar xvf fee-0.0.1-SNAPSHOT.jar META-INF/MANIFEST.MF
    1. Edit the <span>META-INF/MANIFEST.MF</span> file using <span>vim</span>, changing the version numbers of the three Tomcat JAR packages: <span>tomcat-annotations-api</span>, <span>tomcat-embed-core</span>, <span>tomcat-embed-websocket</span> to <span>9.0.87</span>, then save and exit!

    2. Update the <span>META-INF/MANIFEST.MF</span> file back into the original JAR package.

      # 1️⃣ Before updating, back up the original JAR package (name the compressed package as you like) tar -zcvf fee-0.0.1-SNAPSHOT.jar-202404161452-bak.tar.gz fee-0.0.1-SNAPSHOT.jar # 2️⃣ Update the MANIFEST.MF file into the JAR package # Command example: jar uvfm xxx.jar META-INF/MANIFEST.MF # Note: When updating general files into a JAR package, use the uvf parameters. The reason for adding the m parameter here is that MANIFEST.MF is an archive file jar uvfm fee-0.0.1-SNAPSHOT.jar META-INF/MANIFEST.MF

    Command Breakdown

    Let’s break down each part of the command:

    • <span>jar</span>: This is still the command for the Java Archive Tool.

    • <span>uvfm</span>: This is a set of options passed to the <span>jar</span> command.

      • <span>u</span>: Represents “update”. Indicates that an update operation is to be performed on the specified JAR package.
      • <span>v</span>: Represents “verbose”. When executing the command, detailed operation information will be printed in the terminal.
      • <span>f</span>: Represents “file”. Indicates that the name of the JAR package to be operated on is specified on the command line (i.e., <span>fee-0.0.1-SNAPSHOT.jar</span>).
      • <span>m</span>: Represents “manifest”. This is a very critical option. It tells the <span>jar</span> command that you will provide an external manifest file, the contents of which will be used to create or overwrite the internal <span>META-INF/MANIFEST.MF</span> file of the JAR package.
    • Order of Parameters (Very Important) When the <span>m</span> option is used, the <span>jar</span> command has strict requirements on the order of subsequent parameters:<span>jar <options> <target jar file name> <source manifest file name> [other files to add...]</span>

      So in this command:

      • <span>fee-0.0.1-SNAPSHOT.jar</span> is the target JAR file being updated.
      • <span>META-INF/MANIFEST.MF</span> is the external manifest file used as source data.

    Command Execution Process

    • <span>jar</span> tool will prepare to update the archive file named <span>fee-0.0.1-SNAPSHOT.jar</span>.
    • Due to the presence of the <span>m</span> option, the <span>jar</span> tool will recognize the parameter immediately following the JAR file name (i.e., <span>META-INF/MANIFEST.MF</span>) as the path to the source manifest file.
    • <span>jar</span> tool will look for the file named <span>META-INF/MANIFEST.MF</span> in your current working directory. This means that there must be a <span>META-INF</span> folder in your current directory, containing a <span>MANIFEST.MF</span> file.
    • <span>jar</span> tool will read the contents of this external <span>MANIFEST.MF</span> file.
    • Then, it will open the <span>fee-0.0.1-SNAPSHOT.jar</span> file and completely replace the original internal <span>META-INF/MANIFEST.MF</span> file with the contents of the external manifest file just read.
    • This operation is directly modifying<span>fee-0.0.1-SNAPSHOT.jar</span> file itself.
    • Since the <span>v</span> option was used, the terminal will print information similar to “adding: META-INF/MANIFEST.MF” to confirm that the operation has been executed.

    3. Verify that the MANIFEST.MF file in the JAR package has been successfully updated

    vim fee-0.0.1-SNAPSHOT.jar # Move the cursor to the line where MANIFEST.MF is located, press the ENTER key to enter the MANIFEST.MF file, and confirm that the version number has been successfully modified.

    Scenario 3

    Updating dependency JARs in a fat JAR package.

    This uses the default packaging method of Spring Boot. To upgrade the Tomcat version in the JAR package, you cannot directly delete files within the JAR package; you need to extract it first and then repackage it.

    1. Backup and Extract

    # Backup the original JAR package tar -zcvf log-0.0.1.jar-202404161511-bak.tar.gz log-0.0.1.jar # Create a temporary directory and move the log-0.0.1.jar file to that directory for processing, avoiding unnecessary impacts from other configuration files in the same directory during subsequent packaging mkdir tmp mv log-0.0.1.jar tmp cd tmp jar xvf log-0.0.1.jar # Enter the lib directory and delete the old dependency packages cd BOOT-INF/lib rm tomcat-embed-* # Place the upgraded JAR packages in this directory # Confirm that the new packages have been placed in this directory ll|grep tomcat-
    image.png
    # Switch back to the tmp directory and start preparing to repackage cd ../../
    image.png

    2. Repackage the JAR

    # Use store mode to repackage # 0 indicates to the jar command to package files in store mode instead of the default deflate compression mode # You can also specify the original MANIFEST.MF file for packaging jar cfm0 log-0.0.1.jar META-INF/MANIFEST.MF ./ jar cfM0 log-0.0.1.jar ./ # Move log-0.0.1.jar back to the original directory mv log-0.0.1.jar ../

    <span>jar cfM0 log-0.0.1.jar ./</span> This command’s function is: Create a new, completely uncompressed JAR file named <span>log-0.0.1.jar</span>, which contains all files and subdirectories in the current directory, and does not automatically generate a manifest file (MANIFEST.MF).

    Command Breakdown

    • <span>jar</span>: This is the command for the Java Archive Tool.

    • <span>cfM0</span>: This is a combination of options that defines the specific operations to be performed by the <span>jar</span> command.

      • <span>c</span>: Represents “create”. Indicates that a new archive file is to be created.
      • <span>f</span>: Represents “file”. Indicates that the name of the archive file to be created is specified on the command line (i.e., <span>log-0.0.1.jar</span>).
      • <span>M</span>: Represents “no-manifest”. This is a key option. By default, the <span>jar</span> command automatically generates a <span>META-INF/MANIFEST.MF</span> manifest file when creating an archive. Using the <span>M</span> option can prevent this behavior.
      • <span>0</span> (zero): Represents “store only; do not use ZIP compression”. This is another key option. By default, JAR files are compressed using the ZIP algorithm to reduce file size. Using the <span>0</span> option tells the <span>jar</span> tool to completely disable compression, simply storing the files as they are in the archive.
    • <span>log-0.0.1.jar</span>: This is the name of the JAR file to be created.

    • <span>./</span>: This specifies the source of the content to be added to the JAR package.

      • <span>.</span> represents the current directory.
      • <span>./</span> is an explicit representation of the current directory.
      • This parameter tells the <span>jar</span> command: “Package all files and subdirectories (recursively) in the current directory.”

    In-depth Analysis of Key Options <span>M</span> and <span>0</span>

    Why use <span>M</span> (do not create Manifest)?

    <span>META-INF/MANIFEST.MF</span> file is the metadata center of the JAR package, containing version information, creator information, and most importantly, the <span>Main-Class</span> attribute (used to make the JAR executable). You may not want to create it in the following cases:

    • Creating library files: If you are packaging a library that is not a standalone executable program but is referenced by other applications, then it does not need a <span>Main-Class</span>, and the manifest file is not necessary.
    • Custom Manifest: You may plan to manually add a more detailed <span>MANIFEST.MF</span> file later.
    • Packaging non-Java content: Although uncommon, the <span>jar</span> tool is essentially a ZIP tool, and you may just use it to archive some non-Java resources, in which case the manifest file is meaningless.

    Why use <span>0</span> (do not compress)?

    Disabling compression may seem counterintuitive, as we usually want files to be as small as possible. However, in certain specific scenarios, not compressing can be advantageous:

    • Performance and Speed:
      • Packaging Speed: Not compressing makes the packaging process very fast, as the CPU does not need to perform compute-intensive compression operations.
      • Reading Speed: Some application servers or class loaders can read files directly from the JAR package. If the files are not compressed, the decompression step can be skipped, potentially speeding up class loading.
    • Content Already Compressed: If the content you are packaging is already in a compressed format (e.g., <span>.jpg</span>, <span>.png</span>, <span>.mp3</span>, <span>.zip</span> files), compressing them again will hardly reduce the size and will waste CPU resources. In this case, disabling compression is a wise choice.

    Summary of Execution Process

    When you run the <span>jar cfM0 log-0.0.1.jar ./</span> command:

    1. <span>jar</span> tool prepares to create a new file named <span>log-0.0.1.jar</span>.
    2. It begins to recursively scan all content in the current directory (<span>./</span><span>)</span><span>.</span>
    3. It directly stores every scanned file and directory structure into <span>log-0.0.1.jar</span>, without any compression.
    4. Throughout the process, it will not create<span>META-INF/</span> directory and <span>MANIFEST.MF</span> file.
    5. Ultimately, you get an archive package that may be larger (due to no compression) but created very quickly and does not contain a manifest file.

    Leave a Comment