LoginSignup
1
0

More than 3 years have passed since last update.

Spring Initializr で作成したプロジェクトが生成する WAR ファイルの中身を調べる

Posted at

概要

  • Spring Initializr で Gradle と Maven のプロジェクトを作成し、生成した WAR ファイルの中身をしらべる

Spring Initializr で指定する項目

  • Java 11 + Spring Boot 2.2.6
  • Packaging は WAR を指定
  • Dependencies に Spring Web を追加

プロジェクトファイル構成

Spring Initializr で作成したプロジェクトからテストコード等を削って以下のファイル構成にする。

Gradle

├── build.gradle
├── settings.gradle
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           ├── MyappApplication.java
        │           └── ServletInitializer.java
        └── resources
            ├── application.properties
            ├── static
            └── templates

Maven

├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           ├── MyappApplication.java
        │           └── ServletInitializer.java
        └── resources
            ├── application.properties
            ├── static
            └── templates

差異

設定ファイル以外の中身は同じ。

$ diff -r gradle/myapp maven/myapp
Only in gradle/myapp: build.gradle
Only in maven/myapp: pom.xml
Only in gradle/myapp: settings.gradle

ビルド用設定ファイル

外部ライブラリの Apache PDFBox を追加しておく。
これは Spring 以外の外部ライブラリが WAR ファイルにどのように格納されるかを調べるため。

Gradle (build.gradle)

plugins {
  id 'org.springframework.boot' version '2.2.6.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'java'
  id 'war'
}

group = 'com.example'
version = '0.0.1'
sourceCompatibility = '11'

repositories {
  mavenCentral()
}

dependencies {
  // https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox
  implementation 'org.apache.pdfbox:pdfbox:2.0.19'
  implementation 'org.springframework.boot:spring-boot-starter-web'
  providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}

Maven (pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.6.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.example</groupId>
  <artifactId>myapp</artifactId>
  <version>0.0.1</version>
  <packaging>war</packaging>
  <name>myapp</name>
  <description>MyApp project</description>

  <properties>
    <java.version>11</java.version>
  </properties>

  <dependencies>
    <!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
    <dependency>
      <groupId>org.apache.pdfbox</groupId>
      <artifactId>pdfbox</artifactId>
      <version>2.0.19</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
    </dependency>
  </dependencies>

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

</project>

プロジェクトのビルドと WAR ファイル展開

Gradle

Gradle 6.3 を使用。

$ gradle build
$ unzip build/libs/myapp-0.0.1.war -d dest

Maven

Apache Maven 3.6.3 を使用。

$ mvn package
$ unzip target/myapp-0.0.1.war -d dest

WAR ファイル内のファイル構成

  • ソースコードをコンパイルしてできたクラスファイルは WEB-INF/classes に入る
  • Spring 関連の JAR ファイルは WEB-INF/lib に入る
  • 外部ライブラリの JAR ファイルは WEB-INF/lib に入る (Apache PDFBox の pdfbox-2.0.19.jar が WEB-INF/lib にある)
  • tomcat-embed-core-9.0.33.jar など WAR として不要だと思われるファイルは WEB-INF/lib-provided に入る
  • Spring Boot Loader のクラスファイルが org/springframework/boot/loader に入る

Spring Boot 実行可能な Jar 形式 - ドキュメント

依存関係は、ネストされた WEB-INF/lib ディレクトリに配置する必要があります。組み込みの実行時に必要であるが、従来の Web コンテナーにデプロイする場合には不要な依存関係は、WEB-INF/lib-provided に配置する必要があります。

Spring Boot 実行可能な Jar 形式 - ドキュメント

Java は、ネストされた jar ファイル(つまり、jar 内に含まれる jar ファイル)をロードする標準的な方法を提供しません。これは、コマンドラインから展開せずに実行できる自己完結型アプリケーションを配布する必要がある場合に問題になる可能性があります。

この問題を解決するために、多くの開発者は「シェーディングされた」jar ファイルを使用します。シェーディングされた jar は、すべての jar からのすべてのクラスを単一の「uber jar」にパッケージ化します。シェーディングされた jar ファイルの問題は、どのライブラリが実際にアプリケーションに含まれているかを見にくくなることです。また、複数の jar で同じファイル名(ただし、異なるコンテンツ)が使用されている場合、問題が発生する可能性があります。Spring Boot は異なるアプローチを採用しており、実際に jar を直接ネストできます。

Gradle

$ tree dest
dest
├── META-INF
│   └── MANIFEST.MF
├── WEB-INF
│   ├── classes
│   │   ├── application.properties
│   │   ├── com
│   │   │   └── example
│   │   │       ├── MyappApplication.class
│   │   │       └── ServletInitializer.class
│   │   ├── static
│   │   └── templates
│   ├── lib
│   │   ├── classmate-1.5.1.jar
│   │   ├── commons-logging-1.2.jar
│   │   ├── fontbox-2.0.19.jar
│   │   ├── hibernate-validator-6.0.18.Final.jar
│   │   ├── jackson-annotations-2.10.3.jar
│   │   ├── jackson-core-2.10.3.jar
│   │   ├── jackson-databind-2.10.3.jar
│   │   ├── jackson-datatype-jdk8-2.10.3.jar
│   │   ├── jackson-datatype-jsr310-2.10.3.jar
│   │   ├── jackson-module-parameter-names-2.10.3.jar
│   │   ├── jakarta.validation-api-2.0.2.jar
│   │   ├── jboss-logging-3.4.1.Final.jar
│   │   ├── jul-to-slf4j-1.7.30.jar
│   │   ├── log4j-api-2.12.1.jar
│   │   ├── log4j-to-slf4j-2.12.1.jar
│   │   ├── logback-classic-1.2.3.jar
│   │   ├── logback-core-1.2.3.jar
│   │   ├── pdfbox-2.0.19.jar
│   │   ├── slf4j-api-1.7.30.jar
│   │   ├── snakeyaml-1.25.jar
│   │   ├── spring-aop-5.2.5.RELEASE.jar
│   │   ├── spring-beans-5.2.5.RELEASE.jar
│   │   ├── spring-boot-2.2.6.RELEASE.jar
│   │   ├── spring-boot-autoconfigure-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-json-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-logging-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-validation-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-web-2.2.6.RELEASE.jar
│   │   ├── spring-context-5.2.5.RELEASE.jar
│   │   ├── spring-core-5.2.5.RELEASE.jar
│   │   ├── spring-expression-5.2.5.RELEASE.jar
│   │   ├── spring-jcl-5.2.5.RELEASE.jar
│   │   ├── spring-web-5.2.5.RELEASE.jar
│   │   └── spring-webmvc-5.2.5.RELEASE.jar
│   └── lib-provided
│       ├── jakarta.annotation-api-1.3.5.jar
│       ├── spring-boot-starter-tomcat-2.2.6.RELEASE.jar
│       ├── tomcat-embed-core-9.0.33.jar
│       ├── tomcat-embed-el-9.0.33.jar
│       └── tomcat-embed-websocket-9.0.33.jar
└── 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
                │   ├── Archive$Entry.class
                │   ├── Archive$EntryFilter.class
                │   ├── Archive.class
                │   ├── ExplodedArchive$1.class
                │   ├── ExplodedArchive$FileEntry.class
                │   ├── ExplodedArchive$FileEntryIterator$EntryComparator.class
                │   ├── ExplodedArchive$FileEntryIterator.class
                │   ├── ExplodedArchive.class
                │   ├── JarFileArchive$EntryIterator.class
                │   ├── JarFileArchive$JarFileEntry.class
                │   └── JarFileArchive.class
                ├── data
                │   ├── RandomAccessData.class
                │   ├── RandomAccessDataFile$1.class
                │   ├── RandomAccessDataFile$DataInputStream.class
                │   ├── RandomAccessDataFile$FileAccess.class
                │   └── RandomAccessDataFile.class
                ├── jar
                │   ├── AsciiBytes.class
                │   ├── Bytes.class
                │   ├── CentralDirectoryEndRecord$1.class
                │   ├── CentralDirectoryEndRecord$Zip64End.class
                │   ├── CentralDirectoryEndRecord$Zip64Locator.class
                │   ├── CentralDirectoryEndRecord.class
                │   ├── CentralDirectoryFileHeader.class
                │   ├── CentralDirectoryParser.class
                │   ├── CentralDirectoryVisitor.class
                │   ├── FileHeader.class
                │   ├── Handler.class
                │   ├── JarEntry.class
                │   ├── JarEntryFilter.class
                │   ├── JarFile$1.class
                │   ├── JarFile$2.class
                │   ├── JarFile$JarFileType.class
                │   ├── JarFile.class
                │   ├── JarFileEntries$1.class
                │   ├── JarFileEntries$EntryIterator.class
                │   ├── JarFileEntries.class
                │   ├── JarURLConnection$1.class
                │   ├── JarURLConnection$2.class
                │   ├── JarURLConnection$CloseAction.class
                │   ├── JarURLConnection$JarEntryName.class
                │   ├── JarURLConnection.class
                │   ├── StringSequence.class
                │   └── ZipInflaterInputStream.class
                └── util
                    └── SystemPropertyUtils.class

17 directories, 99 files

Maven

$ tree dest
dest
├── META-INF
│   ├── MANIFEST.MF
│   └── maven
│       └── com.example
│           └── myapp
│               ├── pom.properties
│               └── pom.xml
├── WEB-INF
│   ├── classes
│   │   ├── application.properties
│   │   └── com
│   │       └── example
│   │           ├── MyappApplication.class
│   │           └── ServletInitializer.class
│   ├── lib
│   │   ├── classmate-1.5.1.jar
│   │   ├── commons-logging-1.2.jar
│   │   ├── fontbox-2.0.19.jar
│   │   ├── hibernate-validator-6.0.18.Final.jar
│   │   ├── jackson-annotations-2.10.3.jar
│   │   ├── jackson-core-2.10.3.jar
│   │   ├── jackson-databind-2.10.3.jar
│   │   ├── jackson-datatype-jdk8-2.10.3.jar
│   │   ├── jackson-datatype-jsr310-2.10.3.jar
│   │   ├── jackson-module-parameter-names-2.10.3.jar
│   │   ├── jakarta.annotation-api-1.3.5.jar
│   │   ├── jakarta.validation-api-2.0.2.jar
│   │   ├── jboss-logging-3.4.1.Final.jar
│   │   ├── jul-to-slf4j-1.7.30.jar
│   │   ├── log4j-api-2.12.1.jar
│   │   ├── log4j-to-slf4j-2.12.1.jar
│   │   ├── logback-classic-1.2.3.jar
│   │   ├── logback-core-1.2.3.jar
│   │   ├── pdfbox-2.0.19.jar
│   │   ├── slf4j-api-1.7.30.jar
│   │   ├── snakeyaml-1.25.jar
│   │   ├── spring-aop-5.2.5.RELEASE.jar
│   │   ├── spring-beans-5.2.5.RELEASE.jar
│   │   ├── spring-boot-2.2.6.RELEASE.jar
│   │   ├── spring-boot-autoconfigure-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-json-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-logging-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-validation-2.2.6.RELEASE.jar
│   │   ├── spring-boot-starter-web-2.2.6.RELEASE.jar
│   │   ├── spring-context-5.2.5.RELEASE.jar
│   │   ├── spring-core-5.2.5.RELEASE.jar
│   │   ├── spring-expression-5.2.5.RELEASE.jar
│   │   ├── spring-jcl-5.2.5.RELEASE.jar
│   │   ├── spring-web-5.2.5.RELEASE.jar
│   │   └── spring-webmvc-5.2.5.RELEASE.jar
│   └── lib-provided
│       ├── spring-boot-starter-tomcat-2.2.6.RELEASE.jar
│       ├── tomcat-embed-core-9.0.33.jar
│       ├── tomcat-embed-el-9.0.33.jar
│       └── tomcat-embed-websocket-9.0.33.jar
└── 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
                │   ├── Archive$Entry.class
                │   ├── Archive$EntryFilter.class
                │   ├── Archive.class
                │   ├── ExplodedArchive$1.class
                │   ├── ExplodedArchive$FileEntry.class
                │   ├── ExplodedArchive$FileEntryIterator$EntryComparator.class
                │   ├── ExplodedArchive$FileEntryIterator.class
                │   ├── ExplodedArchive.class
                │   ├── JarFileArchive$EntryIterator.class
                │   ├── JarFileArchive$JarFileEntry.class
                │   └── JarFileArchive.class
                ├── data
                │   ├── RandomAccessData.class
                │   ├── RandomAccessDataFile$1.class
                │   ├── RandomAccessDataFile$DataInputStream.class
                │   ├── RandomAccessDataFile$FileAccess.class
                │   └── RandomAccessDataFile.class
                ├── jar
                │   ├── AsciiBytes.class
                │   ├── Bytes.class
                │   ├── CentralDirectoryEndRecord$1.class
                │   ├── CentralDirectoryEndRecord$Zip64End.class
                │   ├── CentralDirectoryEndRecord$Zip64Locator.class
                │   ├── CentralDirectoryEndRecord.class
                │   ├── CentralDirectoryFileHeader.class
                │   ├── CentralDirectoryParser.class
                │   ├── CentralDirectoryVisitor.class
                │   ├── FileHeader.class
                │   ├── Handler.class
                │   ├── JarEntry.class
                │   ├── JarEntryFilter.class
                │   ├── JarFile$1.class
                │   ├── JarFile$2.class
                │   ├── JarFile$JarFileType.class
                │   ├── JarFile.class
                │   ├── JarFileEntries$1.class
                │   ├── JarFileEntries$EntryIterator.class
                │   ├── JarFileEntries.class
                │   ├── JarURLConnection$1.class
                │   ├── JarURLConnection$2.class
                │   ├── JarURLConnection$CloseAction.class
                │   ├── JarURLConnection$JarEntryName.class
                │   ├── JarURLConnection.class
                │   ├── StringSequence.class
                │   └── ZipInflaterInputStream.class
                └── util
                    └── SystemPropertyUtils.class

18 directories, 101 files

差異

大きくは変わらない。

$ diff -r gradle/myapp/dest maven/myapp/dest
diff -r gradle/myapp/dest/META-INF/MANIFEST.MF maven/myapp/dest/META-INF/MANIFEST.MF
1a2,5
> Created-By: Maven Archiver 3.4.0
> Build-Jdk-Spec: 11
> Implementation-Title: myapp
> Implementation-Version: 0.0.1
Only in maven/myapp/dest/META-INF: maven
Only in gradle/myapp/dest/WEB-INF/classes: static
Only in gradle/myapp/dest/WEB-INF/classes: templates
Only in maven/myapp/dest/WEB-INF/lib: jakarta.annotation-api-1.3.5.jar
Only in gradle/myapp/dest/WEB-INF/lib-provided: jakarta.annotation-api-1.3.5.jar
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0