spring boot应用启动原理分析

spring boot quick start

在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启动的,不需要另外配置一个Web Server。

如果之前没有使用过spring boot可以通过下面的demo来感受下。

下面以这个工程为例,演示如何启动Spring boot项目:

git clone git@github.com:hengyunabc/spring-boot-demo.git

mvn spring-boot-demo

java -jar target/demo-0.0.1-SNAPSHOT.jar

如果使用的IDE是spring sts或者idea,可以通过向导来创建spring boot项目。

对spring boot的两个疑问

刚开始接触spring boot时,通常会有这些疑问

spring boot如何启动的?

spring boot embed tomcat是如何工作的? 静态文件,jsp,网页模板这些是如何加载到的?

下面来分析spring boot是如何做到的。

打包为单个jar时,spring boot的启动方式

maven打包之后,会生成两个jar文件:

demo-0.0.1-SNAPSHOT.jar

demo-0.0.1-SNAPSHOT.jar.original

其中demo-0.0.1-SNAPSHOT.jar.original是默认的maven-jar-plugin生成的包。

demo-0.0.1-SNAPSHOT.jar是spring boot maven插件生成的jar包,里面包含了应用的依赖,以及spring boot相关的类。下面称之为fat jar。

先来查看spring boot打好的包的目录结构(不重要的省略掉):

├── META-INF

│ ├── MANIFEST.MF

├── application.properties

├── com

│ └── example

│ └── SpringBootDemoApplication.class

├── lib

│ ├── aopalliance-1.0.jar

│ ├── spring-beans-4.2.3.RELEASE.jar

│ ├── …

└── org

└── springframework

    └── boot

        └── loader

            ├── ExecutableArchiveLauncher.class

            ├── JarLauncher.class

            ├── JavaAgentDetector.class

            ├── LaunchedURLClassLoader.class

            ├── Launcher.class

            ├── MainMethodRunner.class

            ├── ...               

依次来看下这些内容。

MANIFEST.MF

Manifest-Version: 1.0

Start-Class: com.example.SpringBootDemoApplication

Implementation-Vendor-Id: com.example

Spring-Boot-Version: 1.3.0.RELEASE

Created-By: Apache Maven 3.3.3

Build-Jdk: 1.8.0_60

Implementation-Vendor: Pivotal Software, Inc.

Main-Class: org.springframework.boot.loader.JarLauncher

可以看到有Main-Class是org.springframework.boot.loader.JarLauncher ,这个是jar启动的Main函数。

还有一个Start-Class是com.example.SpringBootDemoApplication,这个是我们应用自己的Main函数。

@SpringBootApplication

public class SpringBootDemoApplication {

public static void main(String[] args) {

    SpringApplication.run(SpringBootDemoApplication.class, args);

}

}

com/example 目录

这下面放的是应用的.class文件。

lib目录

这里存放的是应用的Maven依赖的jar包文件。

比如spring-beans,spring-mvc等jar。

org/springframework/boot/loader 目录

这下面存放的是Spring boot loader的.class文件。

Archive的概念

archive即归档文件,这个概念在linux下比较常见

通常就是一个tar/zip格式的压缩包

jar是zip格式

在spring boot里,抽象出了Archive的概念。

一个archive可以是一个jar(JarFileArchive),也可以是一个文件目录(ExplodedArchive)。可以理解为Spring boot抽象出来的统一访问资源的层。

上面的demo-0.0.1-SNAPSHOT.jar 是一个Archive,然后demo-0.0.1-SNAPSHOT.jar里的/lib目录下面的每一个Jar包,也是一个Archive。

public abstract class Archive {

public abstract URL getUrl();

public String getMainClass();

public abstract Collection getEntries();

public abstract List getNestedArchives(EntryFilter filter);

可以看到Archive有一个自己的URL,比如:

jar:file:/tmp/target/demo-0.0.1-SNAPSHOT.jar!/

还有一个getNestedArchives函数,这个实际返回的是demo-0.0.1-SNAPSHOT.jar/lib下面的jar的Archive列表。它们的URL是:

jar:file:/tmp/target/demo-0.0.1-SNAPSHOT.jar!/lib/aopalliance-1.0.jar

jar:file:/tmp/target/demo-0.0.1-SNAPSHOT.jar!/lib/spring-beans-4.2.3.RELEASE.jar

JarLauncher

从MANIFEST.MF可以看到Main函数是JarLauncher,下面来分析它的工作流程。

JarLauncher类的继承结构是:

class JarLauncher extends ExecutableArchiveLauncher

class ExecutableArchiveLauncher extends Launcher

以demo-0.0.1-SNAPSHOT.jar创建一个Archive:

JarLauncher先找到自己所在的jar,即demo-0.0.1-SNAPSHOT.jar的路径,然后创建了一个Archive。

下面的代码展示了如何从一个类找到它的加载的位置的技巧:

protected final Archive createArchive() throws Exception {

ProtectionDomain protectionDomain = getClass().getProtectionDomain();

CodeSource codeSource = protectionDomain.getCodeSource();

URI location = (codeSource == null ? null : codeSource.getLocation().toURI());

String path = (location == null ? null : location.getSchemeSpecificPart());

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);

}

return (root.isDirectory() ? new ExplodedArchive(root)
new JarFileArchive(root));

}

获取lib/下面的jar,并创建一个LaunchedURLClassLoader

JarLauncher创建好Archive之后,通过getNestedArchives函数来获取到demo-0.0.1-SNAPSHOT.jar/lib下面的所有jar文件,并创建为List。

注意上面提到

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值