チャットSpringBootを開始するには、原則としてFatJar

JARファイルとMENIFEST.MFファイルを紹介する記事を書きましたが前に、次を参照してください。チャットJARファイルとMANIFEST.MFは、この記事ではJARファイルの内部構造を説明します。この記事のお得な情報はFatJarアップを実行する方法でSpringBootで、次は紹介して、以前のリズムに従うことを続けます。

ファイルのディレクトリを抽出した後FatJar

春公式サイト空SpringBootエンジニアリングにアイデアや新しいSpringBootエンジニアリング、利便性、お薦めは依存しない、何のプラスにデフォルトで作成することができます。

、Mavenのコマンドでパッケージ構築に成功し、パッケージ製品のショットの後に得られたとして、次のとおりです。

前回の記事に記載された、ジャーパッケージは、zipパッケージの変異体であり、したがって、解凍することによって解凍することができます

unzip -q guides-for-jarlaunch-0.0.1-SNAPSHOT.jar -d mock
复制代码

解凍後FatJarを次のようにディレクトリ構造全体を見るために命令を使用して解凍モックディレクトリツリー(一部省略):

.
├── 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 相关的依赖简写
│       ├── logback-xxx.jar # 表示 logback 相关的依赖简写
│       ├── slf4j-api-1.7.28.jar
│       ├── snakeyaml-1.25.jar
│       ├── spring-xxx.jar   # 表示 spring 相关的依赖简写
├── 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

复制代码

解凍後の3つのフォルダを含むビューの簡単なポイント、FatJar:

├── BOOT-INF # 存放的是业务相关的,包括业务开发的类和配置文件,以及依赖的jar
│   ├── classes
│   └── lib
├── META-INF # 包括 MANIFEST.MF 描述文件和 maven 的构建信息
│   ├── MANIFEST.MF
│   └── maven
└── org # SpringBoot 相关的类
    └── springframework
复制代码

私たちは通常、通常SpringApplication#のrunメソッドから始まる、デバッグプロセスSpringBootプロジェクトの開始します

@SpringBootApplication
public class BootStrap {
    public static void main(String[] args) {
        // 入口
        SpringApplication.run(BootStrap.class,args);
    }
}
复制代码

Javaプログラムのために、私たちは正面玄関スタート機能がなければならないことを知って、ここでは、資格のあるように見えますが、主な機能とコマンドjavaクラスによって実行されたときに一つのことは、つまりは、-jarパラメータを持つことが必要とされていませんたとえば、新しいファイルBootStrap.javaを作成し、こう述べています。

public class BootStrap {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}
复制代码

javacがこのファイルをコンパイルします。

javac BootStrap.java
复制代码

その後、BootStrap.classは、javaコマンドで直接実行することができた.classファイルをコンパイルした後に得ることができます。

java BootStrap  # 输出 Hello World
复制代码

だから-jar javaに関する?実際には、このジャワの公式文書は、の明確な説明は次のとおりです。

  • -jarファイル名

JARファイル内にカプセル化されたプログラムを実行します。アプリケーションの起動ポイントとして機能無効メイン(文字列[] args)メソッドのpublic staticでクラスを定義してクラス名:filename引数はフォームのメインクラスに行が含まれていることをマニフェストとJARファイルの名前です。

あなたが-jarオプションを使用すると、指定されたJARファイルには、すべてのユーザクラスの源であり、他のクラスパスの設定は無視されます。

それは単にのjava -jarコマンドは、特定の起動クラスはメインクラス属性MANIFEST.MFリソースに設定する必要があります起動するように、です。

その裏には、ファイルを見つけ、解凍した後、再び前に、圧縮ファイルのディレクトリを見て/META-INF/MANIFEST.MF、メタデータを見て:

Manifest-Version: 1.0
Implementation-Title: guides-for-jarlaunch
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.glmapper.bridge.boot.BootStrap
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.2.0.RELEASE
Created-By: Maven Archiver 3.4.0
# Main-Class 在这里,指向的是 JarLauncher
Main-Class: org.springframework.boot.loader.JarLauncher
复制代码

org.springframework.boot.loader.JarLauncher ORG / springframework /ブート/ブートローダ以下のクラスに保存されています:

└── boot
    └── loader
        ├── ExecutableArchiveLauncher.class
        ├── JarLauncher.class  # JarLauncher
        ├── # 省略
复制代码

これは、実質的に、FatJarの出現をまっすぐ、org.springframework.boot.loaderクラスは、入口、BOOT-INF格納されたサービスコードとに依存して、META-INFを記述するメタデータが存在するとして、次のブートSpringBootエンジニアリングの責任です。

JarLaunch - FatJarスターター

ここに挿入JarLaunchを、分析する前に、org.springframework.boot.loaderの下でこれらのクラスは、それらがFatJar内部にパッケージされていますか

春・ブートのMavenプラグイン・パッケージのスプリング・ブート・ローダプロセス

新しい空のSpringBootプロジェクトに導入するクラスの作成や表示中のどこかには関係ありませんので。実際には、それぞれの新しいSpringBootプロジェクトのために、彼らのpom.xmlファイルに以下のプラグインを参照してください。

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
复制代码

これはSpringBoot公式プラグインパッケージFatJarためで、org.springframework.boot.loaderクラスでは、実際にこのプラグイン経由で破壊されました。

ここでは、このプラグインはFatJar実行フローに関連するクラスローダです。

org.springframework.boot.maven#execute-> org.springframework.boot.maven#再パッケージ - > org.springframework.boot.loader.tools.Repackager#repackage-> org.springframework.boot.loader.tools.Repackager#writeLoaderClasses - > org.springframework.boot.loader.tools.JarWriter#writeLoaderClasses

最後の方法は、方法の効果は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);
}
复制代码

JarLaunch基本原則

上記の分析に基づいて、ここでの問題を考える、JavaのブートストラップSpringBootプロジェクト直接で直接実行することができますか?このようなパラメータJarLaunchガイド-jar必要がなく、理論的ではないかもしれ最も原始的な命令のJavaを直接、mainメソッドので。

よるjava BootStrap方法開始

ブートストラップ・カテゴリ次のように:

@SpringBootApplication
public class BootStrap {
    public static void main(String[] args) {
        SpringApplication.run(BootStrap.class,args);
    }
}
复制代码

コンパイル後、実行はjava com.glmapper.bridge.boot.BootStrap、その後、投げ:

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このクラスから、ここでは実際には非常によく理解されて、ブートストラップがSpringApplicationクラスを導入しましたが、このクラスには、起動時にjavaのコマンドBOOT-INF / libの下にあり、クラスパスが指定されていません。

直接のjavaコマンドを使用して正常に実行さ、歓迎のメッセージ通信がある場合は、ここでそれらを繰り返すない、-classpath + -Xbootclasspath次を試しによって、一見仕事は、しません。

によって java JarLaunch 启动

スルーjava org.springframework.boot.loader.JarLauncherを開始するための方法、あなたはそれが可能である見ることができます。

JarLauncherの道を開始したときにここでは、基本的には、いくつかの方法でブートストラップで導入された従属として必要なJARファイルに依存しますが、推測することができます。ここでJarLauncher開始下の簡単な分析は、ブートクラスとして、それがどのようなんです。

ファンダメンタル分析

定義されJarLaunchクラスは次のとおりです。

public class JarLauncher extends ExecutableArchiveLauncher {
    // BOOT-INF/classes/
    static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";
    // BOOT-INF/lib/
    static final String BOOT_INF_LIB = "BOOT-INF/lib/";
    // 空构造函数
    public JarLauncher() {
    }
    // 带有指定 Archive 的构造函数
    protected JarLauncher(Archive archive) {
    	super(archive);
    }
    // 是否是可嵌套的对象
    @Override
    protected boolean isNestedArchive(Archive.Entry entry) {
    	if (entry.isDirectory()) {
    		return entry.getName().equals(BOOT_INF_CLASSES);
    	}
    	return entry.getName().startsWith(BOOT_INF_LIB);
    }
    
    // main 函数
    public static void main(String[] args) throws Exception {
    	new JarLauncher().launch(args);
    }

}
复制代码

コードによって、我々は明らかにいくつかの重要な情報ポイントを見ることができます:

  • BOOT_INF_CLASSESそして、BOOT_INF_LIB後に2つのフロント解凍ファイルのディレクトリに対応する2つの定数
  • JarLaunchは、ブートエントリとして主な機能が含まれています

しかし、単にビューの主なポイントから、ちょうどJarLaunchオブジェクトを構築し、その打ち上げの方法を実行し、私たちはどこに必要な依存関係の建物を見て期待していませんでした。実際には、この部分はJarLaunchでExecutableArchiveLauncherが達成親クラスのコンストラクタです。

public ExecutableArchiveLauncher() {
    try {
        // 构建 archive 
    	this.archive = createArchive();
    }
    catch (Exception ex) {
    	throw new IllegalStateException(ex);
    }
}

// 构建 Archive
protected final Archive createArchive() throws Exception {
    ProtectionDomain protectionDomain = getClass().getProtectionDomain();
    CodeSource codeSource = protectionDomain.getCodeSource();
    URI location = (codeSource != null) ? codeSource.getLocation().toURI() : null;
    // 这里就是拿到当前的 classpath 
    // /Users/xxx/Documents/test/glmapper-springboot-study-guides/guides-for-jarlaunch/target/mock/
    String path = (location != null) ? location.getSchemeSpecificPart() : null;
    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);
    }
    // 构建 Archive 
    return (root.isDirectory() ? new ExplodedArchive(root) : new JarFileArchive(root));
}
复制代码

PS:ここでは紙面の都合のアーカイブのコンセプトについて、説明着手することはありません。

上記のように構成することでアーカイブした後、打ち上げの方法に進みます。

protected void launch(String[] args) throws Exception {
    // 注册协议,利用了 java.net.URLStreamHandler 的扩展机制,SpringBoot
    // 扩展出了一种可以解析 jar in jar 的协议
    JarFile.registerUrlProtocolHandler();
    // 通过 classpath 来构建一个 ClassLoader
    ClassLoader classLoader = createClassLoader(getClassPathArchives());
    // launch 
    launch(args, getMainClass(), classLoader);
}
复制代码

次の値が(getMainClass下の方法に焦点を当てる必要があります)することができ、ここでMENIFEST.MFは、ブートストラップ・カテゴリ内の、実際には、私たちの技術をスタートクラスを指定し得ることです:

@Override
protected String getMainClass() throws Exception {
    // 从 archive 中拿到 Manifest
    Manifest manifest = this.archive.getManifest();
    String mainClass = null;
    if (manifest != null) {
        // 获取 Start-Class
    	mainClass = manifest.getMainAttributes().getValue("Start-Class");
    }
    if (mainClass == null) {
    	throw new IllegalStateException(
    			"No 'Start-Class' manifest entry specified in " + this);
    }
    // 返回 mainClass
    return mainClass;
}
复制代码

次いで、最終的なオブジェクトのMainMethodRunnerインスタンスによって構築物によって反射によってクラスブートストラップの主なメソッドを呼び出します。

概要

起動するSpringBootの道の下JarLaunchの観点から、この記事で、そのような簡単なデモの起動モードとしてのjava -jar javaの従来の方法で、簡単にはJarLaunchが開始の下で、基本的な原理を説明しながら。さらに問い合わせを行うことなく、アーカイブ、ハンドラおよびその他のカスタムプロトコルを構築しているために、関連ポイントの独立した分析を行うために戻ってきます。

おすすめ

転載: juejin.im/post/5dc9507be51d45694b48667b