作为springMVC项目结构的延伸,springboot项目结构在初创之始将开发者在前端和后台之间连接的逻辑编辑方式(包括参数之间的映射关系和接口、服务、数据三者之间的通信)作为约定俗称封装成多个依赖,使开发者在开发项目之时只要引入相关的依赖和注释,即可顺利建立以往需要编写多个servlet逻辑和相关xml配置而完成的工作,从而大大简化了开发者所需编写的代码复杂度,减小了工作量。然而,在不知道项目逻辑和依赖的情况下,springboot的加载方式很难仅从代码上来理解,本文就此对springboot项目的一般加载方式和逻辑进行分析,其中有不少个人理解,可能有误,在此备注供日后修正。
无论在任何一种项目管理模式下,开发基于已有架构的项目都需要配置相应的运行环境,即所谓的项目依赖。在基于maven的管理模式下,配置相关的文件会根据环境配置文件pom.xml)所给出的配置在本地服务器或者远程服务器加载相关的jar包并自动加入环境依赖列表。maven的开发环境配置的pom.xml格式在此链接中有详细解释,在此不做过多解释:http://blog.csdn.net/u013631223/article/details/79133287
下面以这个工程为例,演示如何启动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
maven打包后,生成两个以项目名和版本号为根据自动生成的两个包
demo-0.0.1-SNAPSHOT.jar
demo-0.0.1-SNAPSHOT.jar.original
其中,demo-0.0.1-SNAPSHOT.jar是spring boot maven插件生成的jar包,里面包含了应用的依赖,以及spring boot相关的类。下面称之为fat jar。demo-0.0.1-SNAPSHOT.jar.original是默认的maven-jar-plugin生成的包。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
标注文件MANIFEST.MF是对jar包的描述文件,执行jar时虚拟机会根据这个文件对相关的资源和执行入口进行搜索从而完成功能执行。关于MANIFEST文件的解释可以参考如下链接http://blog.csdn.net/u013631223/article/details/79136469
根据该文件可以看到有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);
}
}
SpringApplication是Springboot项目的启动基础配置相关类,包括环境初始化和程序入口等,上述.run()函数即为程序入口,在此不做过多解释。
com/example 目录
这下面放的是应用的.class文件。
lib目录
这里存放的是应用的依据Maven依赖配置从仓库下载的jar包文件。
比如spring-beans,spring-mvc等jar。
org/springframework/boot/loader 目录
这下面存放的是Spring boot loader的.class文件。根据官网文件的叙述点击打开链接,似乎Springboot loader的作用只是让Springboot可以支持运行架构之外的额外jar包,具体怎么做到的还没看到,说不定理解有误,做个标记
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<Entry> getEntries();
public abstract List<Archive> 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
可以看到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可以看到jar的Main函数是JarLauncher,下面来分析它的工作流程。
JarLauncher类的继承结构是: