SpringBoot从宏观上说,就是对spring容器进行了一层包装。它内部的入口是利用 SpringApplication类的static的 run 方法进行启动的,调用的图:

  

上图中的这些方法都位于org.springframework.boot.SpringApplication这个类中,由此可见SpringApplication这个类在springboot框架中的作用。

//调用示例:

public static void main(String[] args) throws Exception {
  SpringApplication.run(Examples.class, args);
}

SpringApplication类提供了两个static的run方法:

public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
} public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}

上面两个方法其实就是一个,最终都会创建一个SringApplication实例,在构造时会处理传入的 sources 参数,而且这souces类可以是多个,调用的方式还可以这样:

public static void main(String[] args) throws Exception {

  Class<?>[] primarySources = new Class<?>[] { Examples.class , Examples1.class } ;
  SpringApplication.run( primarySources , args);
}

SpringApplication构造方法如下:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  this.resourceLoader = resourceLoader;
  Assert.notNull(primarySources, "PrimarySources must not be null");
  this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  this.webApplicationType = WebApplicationType.deduceFromClasspath();   //用来查找每个jar和类路径下的/META-INF/spring.factories文件,并获取其中的特定接口的配置的
  setInitializers((Collection) getSpringFactoriesInstances(
  ApplicationContextInitializer.class)); //找出每个jar和类路径下的/META-INF/spring.factories文件中配置的ApplicationContextInitializer类
  setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));   this.mainApplicationClass = deduceMainApplicationClass(); //推断出带有main方法的运行类
}

上面的代码通过构造完成初始化之后,紧接着就是调用SpringApplication类的实例 run方法,代码如下:

public ConfigurableApplicationContext run(String... args) {
//StopWatch作用是用来统计spring实例运行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start(); //ConfigurableApplicationContext接口提供了对Spring容器的配置功能
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 1. 会执行ApplicationContextInitializer接口进行初始化工作
// 2. 对外发布监听事件
// 3. 优先创建有特定作用的单例bean
// 4. 把带有main方法的主类作为bean的配置源,并从配置源中加载bean信息到容器中
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//spring容器的生命周期处理,该方法完成后单例bean实例就创建了
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//对外发布监听事件
listeners.started(context);
//我们在开发中可能会有这样的情景。需要在容器启动的时候执行一些内容。比如读取配置文件,数据库连接之类的。SpringBoot给我们提供了两个接口来帮助我们实现这种需求。这两个接口分别为CommandLineRunner和ApplicationRunner。他们的执行时机为容器启动完成的时候。
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方法执行完成,该方法主要是完成spring容器的创建和启动

2. Spring Boot项目启动原理初探的更多相关文章

  1. 让Spring Boot项目启动时可以根据自定义配置决定初始化哪些Bean

    让Spring Boot项目启动时可以根据自定义配置决定初始化哪些Bean 问题描述 实现思路 思路一 [不符合要求] 思路二[满足要求] 思路三[未试验] 问题描述 目前我工作环境下,后端主要的框架 ...

  2. spring boot 项目启动无任何反应

    遇到的问题 spring boot项目启动后无任何报错,ps有进程,nohub无日志 定位 更换jar包,问题依然存在,将jar包放到其他服务器,运行正常,排除打包问题 同服务器其他系统运行正常,但停 ...

  3. spring boot应用启动原理分析

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

  4. Spring Boot应用启动原理分析(转)

    在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启动的,不需要另外配置一个Web Server. 如果之前没有使用过sprin ...

  5. spring boot项目启动报DataSource错误

    初建一个简单的spring boot 项目,启动后会报错. Exception encountered during context initialization - cancelling refre ...

  6. 创建spring boot项目启动报错遇到的问题

    1.Spring boot,Mybatis 启动报错 Failed to auto-configure a DataSource *************************** APPLICA ...

  7. spring boot项目启动报(No session repository could be auto-configured, check your configuration (session store type is 'null'))

    找到项目的application配置文件,增加 spring.session.store-type=none,重新启动问题解决 注:因为项目未使用redis管理session,可以如上设置,如果想使用 ...

  8. spring boot 项目启动无法访问,排查

    查看docker日志,后台应用正常启动,定时任务正常执行,但是前端无法访问到后端接口,点击提示系统错误,解压出项目二级域名,访问域名,报错:Kong Error,说明Kong路由转发没有绑定项目端口, ...

  9. spring boot项目启动报错

    在eclipse中运行没有任何问题,项目挪到idea之后就报错 Unable to start EmbeddedWebApplicationContext due to miss EmbeddedSe ...

随机推荐

  1. Linux下常用的shell操作

    # 设定hosts解析记录 sh-4.2# echo "$(ifconfig ens192 | awk '/\<inet\>/{print $2}') $(hostname)&q ...

  2. Web API中的路由(一)——约定路由

    一.Web API中的路由概念 路由的作用用一句话说明:通过request的uri找到处理该请求的Controller,Action,以及给Action的参数赋值. 一些路由的基本概念: route: ...

  3. javascript的作用域和闭包(三)闭包与模块

    一些很重要的说明:前面三篇博客详细的介绍了,引擎与编译器和作用域的关系,重点需要理解的是编译器中的分词与词法分析,JavaScript的特有的“赋值操作的左右侧”引用操作:编译阶段的词法作用域的工作原 ...

  4. vee-validate表单验证组件

    vee-validate是VUE的基于模板的验证框架,允许您验证输入并显示错误 安装 npm i vee-validate --save 引入 import Vue from 'vue'; impor ...

  5. Objects类的静态方法

    提供了几个静态方法,比如进行对象之间的比较等,而又因为Object是任何对象的超类,因为每个对象都可以调用这几个方法. 1.equals方法 可以防止空指针异常 String s1 = null; S ...

  6. Spring使用事务增加的注解实现方

    以下是我的文件结构 步骤1:配置数据源 <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDa ...

  7. CSRF与SSRF区别

    CSRF 攻击者盗用了你的身份,以你的名义发送恶意请求.CSRF能够做的事情包括:以你的名义发送邮件,发消息,盗用你的账号,甚至于购买商品,虚拟货币转账... 发生条件: 1.登录受信任网站A,并在本 ...

  8. Linux之Ubuntu下DSL拨号上网

    可视化桌面配置方法 1.编辑连接 2.选择 增加 3.选择 DSL 4.选择 新建连接[cmcc@gx属于移动校园用户的ISP指定后缀] 6.OK 当然,还有其他拨号上网的办法: [Linux/Ubu ...

  9. 第19月第20天 UITableView:改变 TableHeaderView 的高度 获取目录大小

    1.UITableView:改变 TableHeaderView 的高度 CGRect newFrame = headerView.frame; newFrame.size.height = newF ...

  10. 【JS】空格分隔手机号

    '88888888888'.replace(/^(.{3})(.*)(.{4})$/, '$1 $2 $3')