目录
方式2:通过spring-boot-dependencies
AnnotationConfigEmbeddedWebApplicationContext
目标
讲述通过源码了解的springboot启动原理与扩展点,并以输出流程图。
what
对spring框架和第三方jar包进行分组,依赖AutoConfiguration特性,快速搭建Spring应用。
构建系统
方式1:继承starter parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
方式2:通过spring-boot-dependencies
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Main入口类
//直接使用run方法,其他配置交给properties文件吧。
@SpringBootApplication
public class Application{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
打包为可执行的jar
需要添加spring-boot-maven-plugin
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
mvn package
通过源码看原理
启动流程图
主要类
EmbeddedWebApplicationContext
作为WebApplicationContext,通过内部的EmbeddedServletContainerFactory bean进行自行引导。
通过EmbeddedServletContainerFactory进行EmbeddedServletContainer的创建、初始化、运行。
EmbeddedServletContainerFactory支持Spring IOC、生命周期回调、属性占位符变量等。
嵌入servlet容器将自动注册Filter和Servlet
只有一个servlet,将mapping '/';任何命名为dispatcherServlet的Servlet,将mapping '/';
多个servlet,则小写bean name将作为mapping前缀;
任何Filer将mapping '/*'。
AnnotationConfigEmbeddedWebApplicationContext
对如下注解类进行注册
- 使用@Configuration的类
- 使用@Component的类
- 符合JSR-330的依赖注入javax.inject
覆盖规则
多个@Configuration类型,加载顺序靠后的@Bean将覆盖顺序靠前的@Bean,可用于外部Configuration Bean覆盖内部Configuration Bean
ConfigFileApplicationListener
org.springframework.boot.context.config.ConfigFileApplicationListener
作为org.springframework.boot.env.EnvironmentPostProcessor的实现类,处理ApplicationEnvironmentPreparedEvent事件
驱动使用springFactoriesLoader去实例化EnvironmentPostProcessor的其他实现,如完成加载本地配置文件,确定activeProfile, application[-profile].properties/yml
BeanFactoryPostProcessor
在BeanFactory实例初始化完成后,执行该扩展,例如覆盖或添加property/bean。
BeanPostProcessor
bean生命周期接口
beanFactory的钩子,允许对新建bean实例进行自定义修改
SpringApplication
从java main方法开启,引导和启动一个Spring应用。
configurationProperties
作用
- 通过前缀,批量匹配与使用外部配置属性。
注意
- field必须有getter setter方法
- 因为未继承@Component注解,需要与@Component相关注解(@Service @Component @Configuration)一起使用,以便被视为bean。
-
@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ConfigurationProperties {}
-
与@Value对比
- 简洁
前缀+fieldName路径,批量匹配外部配置;
@Value必须在类中列举key并使用 ${}占位符 - 类型识别
支持类型识别,@Value 所有val类型识别为String
可执行Jar(fat jar)
why
java本身不支持加载嵌套jar,即jar中包含jar。
how
spring boot可执行jar的目录结构
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-BOOT-INF
+-classes //应用程序的class
| +-mycompany
| +-project
| +-YourClasses.class
+-lib //应用依赖的jar
+-dependency1.jar
+-dependency2.jar
如何从标准jar或嵌套jar中加载内容
org.springframework.boot.loader.jar.JarFile
- 如何定位资源
使用最外层jar的物理文件偏移量表示每个资源(如应用程序class\嵌套jar中的class等)的位置。
来自spring官网
- 如何加载资源
仅需要定位到外层jar的合适部分,不需要解压也不需要将jar全部读入到内存,然后交由springboot自定义的classloader去做。
如何启动jar
org.springframework.boot.loader.Launcher
特殊的引导程序,作为可执行jar的main-class入口,工作流程概述为创建合适的urlclassloader、加载资源、调用应用程序的main()
子类
- JarLauncher 加载嵌套jar的资源,BOOT_INF/lib
- WarLauncher 加载嵌套war的资源,WEB_INF/lib,WEB-INF/lib-provided/
- PropertiesLauncher
META-INF/MANIFEST.MF
Main-Class 指定具体的launcher
Start-Class 指定应用程序的main()所在类
例如
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.xx.xx.MyApplication
启动流程
- bootstrapClassLoader加载jre
- 创建系统类加载器,由系统类加载器加载JarLauncher,反射并执行jarLauncher的main();
- launcher创建LaunchedURLClassLoader并指定资源为所有嵌套jar的uri;
- 将LaunchedURLClassLoader设置为Thread contextClassLoader,用其加载Start-Class,反射获取main方法并执行。
- SpringApplication.run()流程
启动的应用程序只能使用Thread contextClassLoader进行加载,使用systemClassLoader加载嵌套jar将会失败。