1.5 Spring Boot 启动原理解析

前言

前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏。所以这次就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘。

1.5.1 SpringBootApplication背后的秘密


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
……
}

虽然定义使用了多个Annotation进行了原信息标注,但实际上重要的只有三个Annotation:

  • @Configuration(@SpringBootConfiguration点开查看发现里面还是应用了@Configuration)
  • @EnableAutoConfiguration
  • @ComponentScan
1.5.1.1 @Configuration注解

这里的@Configuration对我们来说不陌生,它就是JavaConfig形式的Spring Ioc容器的配置类使用的那个@Configuration,SpringBoot社区推荐使用基于JavaConfig的配置形式,所以,这里的启动类标注了@Configuration之后,本身其实也是一个IoC容器的配置类。

举几个简单例子回顾下,XML跟config配置方式的区别:

1.5.1.1.1 表达形式层面
  • 基于XML配置的方式是这样
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
default-lazy-init="true">
<!--bean定义-->
</beans>
  • JavaConfig的配置方式是这样
@Configuration
public class MockConfiguration{
//bean定义
}

任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类。

1.5.1.1.2 注册bean定义层面
  • ,基于XML的配置形式是这样:
<bean id="mockService" class="..MockServiceImpl">
...
</bean>
  • 而基于JavaConfig的配置形式是这样的:
@Configuration
public class MockConfiguration{
@Bean
public MockService mockService(){
return new MockServiceImpl();
}
}

任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成该bean定义的id。

1.5.1.1.3 表达依赖注入关系层面
  • 为了表达bean与bean之间的依赖关系,在XML形式中一般是这样:
<bean id="mockService" class="..MockServiceImpl">
<propery name ="dependencyService" ref="dependencyService" />
</bean> <bean id="dependencyService" class="DependencyServiceImpl"></bean>
  • 而基于JavaConfig的配置形式是这样的:
@Configuration
public class MockConfiguration{
@Bean
public MockService mockService(){
return new MockServiceImpl(dependencyService());
} @Bean
public DependencyService dependencyService(){
return new DependencyServiceImpl();
}
}

如果一个bean的定义依赖其他bean,则直接调用对应的JavaConfig类中依赖bean的创建方法就可以了。

1.5.1.2 @ComponentScan 注解

@ComponentScan这个注解在Spring中很重要,它对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。

我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。

注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。

1.5.1.3 @EnableAutoConfiguration 注解

详见 1.4 Spring Boot 自动配置原理

1.5.2 SpringApplication执行流程

1.5.2.1 SpringApplication.run()源码分析
public ConfigurableApplicationContext run(String... args) {
// 时间监控
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true,系统变量默认为true
configureHeadlessProperty();
// 获取spring.factories中的监听器变量,args为指定的参数数组,默认为当前类SpringApplication
//第一步:获取并启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//第二步:构造容器环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 设置需要忽略的bean
configureIgnoreBeanInfo(environment);
// 打印banner
Banner printedBanner = printBanner(environment);
//第三步:创建容器
context = createApplicationContext();
//第四步:实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//第五步:准备容器
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//第六步:刷新容器
refreshContext(context);
//第七步:刷新容器后的扩展接口
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
} try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

SpringApplication的run方法的实现是我们本次旅程的主要线路,该方法的主要流程大体可以归纳如下:

  • 第一步:获取并启动监听器
  • 第二步:构造容器环境
  • 第三步:创建容器
  • 第四步:实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
  • 第五步:准备容器
  • 第六步:刷新容器
  • 第七步:刷新容器后的扩展接口

5、Spring Boot 2.x 启动原理解析的更多相关文章

  1. spring boot(二):启动原理解析

    我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static voi ...

  2. spring boot中servlet启动原理

    启动过程及原理 1 spring boot 应用启动运行run方法 StopWatch stopWatch = new StopWatch(); stopWatch.start(); Configur ...

  3. Spring Boot 静态资源访问原理解析

    一.前言 springboot配置静态资源方式是多种多样,接下来我会介绍其中几种方式,并解析一下其中的原理. 二.使用properties属性进行配置 应该说 spring.mvc.static-pa ...

  4. Spring Boot的自动配置原理及启动流程源码分析

    概述 Spring Boot 应用目前应该是 Java 中用得最多的框架了吧.其中 Spring Boot 最具特点之一就是自动配置,基于Spring Boot 的自动配置,我们可以很快集成某个模块, ...

  5. Spring Boot干货系列:(三)启动原理解析

    Spring Boot干货系列:(三)启动原理解析 2017-03-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说 ...

  6. Spring Boot启动原理解析

    Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置 ...

  7. Spring Boot 文件上传原理

    首先我们要知道什么是Spring Boot,这里简单说一下,Spring Boot可以看作是一个框架中的框架--->集成了各种框架,像security.jpa.data.cloud等等,它无须关 ...

  8. 涨姿势:Spring Boot 2.x 启动全过程源码分析

    目录 SpringApplication 实例 run 方法运行过程 总结 上篇<Spring Boot 2.x 启动全过程源码分析(一)入口类剖析>我们分析了 Spring Boot 入 ...

  9. spring boot插件开发实战和原理

    本文转载自spring boot插件开发实战和原理 实战:编写spring boot插件 为什么要编写boot插件 因为我们在开发的时候需要提供一些共同的功能,所以我们编写个共同的jar包.开发人员在 ...

随机推荐

  1. MapReduce的输入文件是两个

    [学习笔记] 1.对于MapReduce程序,如何输入文件是两个文件? 这一小节,我们将继续第一章大数据入门的HelloWorld例子做进一步的研究.这里,我们研究如何输入文件是两个文件.packag ...

  2. 《Mysql - 我的Mysql为什么会抖一下?》

    一: 抖一下? - 平时的工作中,不知道有没有遇到过这样的场景. - 一条 SQL 语句,正常执行的时候特别快,但是有时也不知道怎么回事,它就会变得特别慢. - 并且这样的场景很难复现,它不只随机,而 ...

  3. Python习题006

    作业一:打印10*10  星星 ★☆ 要求一:普通打印★ l = 0 while l <10: h = 0 while h < 9: print("★", end=&q ...

  4. 20191011-构建我们公司自己的自动化接口测试框架-Util的读取excel常用方法模块

    包括获取excel的sheet名字,设定excel的sheet,读excel,写excel等常规操作. from openpyxl import Workbook from openpyxl impo ...

  5. Scratch编程:牛顿的苹果——地心引力

    牛顿的苹果 同学们,你们知道牛顿的苹果的故事吗? 传说1665年秋季,牛顿坐在自家院中的苹果树下苦思着行星绕日运动的原因.这时,一只苹果恰巧落下来,它落在牛顿的脚边.就是这个偶尔的瞬间,牛顿发现了苹果 ...

  6. JS 05 json

    1.下载jar包: https://www.github.com/alibaba/fastjson/releases https://www.mvnrepository.com/artifact/co ...

  7. 剑指offer(9)——用两个栈实现队列

    题目: 用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能. 思路: 首先定义两个栈stack1. ...

  8. js文件分段上传

    前端代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/T ...

  9. nodejs 对 png 图片的像素级别处理

    使用node对图片的像素进行处理 这里使用常见的图片灰度处理为例子: 用到了 pngjs 的 npm 库,这个库可以将 png 的图片文件 Buffer 流,转换为 r g b a 为 255 的像素 ...

  10. SQL Server 2017命令创建新账户(test-user),并分配数据库权限

    -- 1. 创建登录账号USE [master];GOCREATE LOGIN [test-user] WITH PASSWORD = 'xysu7SZ193SNX6E{{HxubPE3}vr',DE ...