最近这两年springboot突然火起来了,那么我们就来看看springboot的运行原理。

一。springboot的三种启动方式:

1.运行带有main方法的
2.通过命令 Java -jar命令
3.通过spring-boot-plugin的方式

二。springboot 启动时执行方法,有两种方式

第一种方式是用启动时的main方法加载静态方法。

另一种是用初始化注解@postconstruct 执行。(注意点必须void并且参数)。

注意点:【1.@PostConstruct会先被执行,静态方法后被执行。2.如果需要参数的话,只能用静态方法的方式

SpringBoot启动过程原理

从上面代码看,调用了SpringApplication的静态方法run。这个run方法会构造一个SpringApplication的实例,然后再调用这里实例的run方法就表示启动SpringBoot。

具体对象处理流程看下边时序图:

概述:

1.构造SpringApplication的实例(时序图步骤1-2)
2.调用SpringApplication.run()方法(时序图步骤3)
3.构造SpringApplicationRunListeners 实例(时序图步骤3.1.1)
4.发布ApplicationStartedEvent事件(时序图步骤3.1.2)
5.SpringApplicationRunListeners 实例准备环境信息(时序图步骤3.1.3)
6.创建ApplicationContext对象(时序图步骤3.1.4)
7.ApplicationContext实例准备环境信息(时序图步骤3.1.5)
8.刷新的上下文(时序图步骤3.1.6)

2.启动加载过程分析

1.2.1 构造SpringApplication的实例(时序图步骤1-2)
代码 public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
// 步骤1
return new SpringApplication(sources).run(args);
}
public SpringApplication(Object... sources) {
// 步骤1.1
initialize(sources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
//加载META-INF/spring.factories路径ApplicationContextInitializer.class
getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection)
//加载META-INF/spring.factories路径ApplicationListener.class
getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

分析
⑴.通过ClassLoader.getResources加载META-INF/spring.factories路径下的
文件信息,从中找key为ApplicationContextInitializer.class,并实例化。
⑵.通过ClassLoader.getResources加载META-INF/spring.factories路径下的
文件信息ApplicationListener.class对应类,并实例化。

1.2.2 调用SpringApplication.run()方法(时序图步骤3)
代码: public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
// 步骤3.1.1
SpringApplicationRunListeners listeners = getRunListeners(args);
// 步骤3.1.2
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 步骤 3.1.3
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
// 步骤3.1.4
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
// 步骤3.1.5
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 步骤3.1.6
refreshContext(context);
// 步骤3.1.7
afterRefresh(context, applicationArguments);
// 步骤3.1.8
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
1.2.2 步骤3.1.1:
代码 private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// (1)
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
1
2
3
4
5
6
分析
(1). 通过ClassLoader.getResources加载META-INF/spring.factories路径下的
文件信息,从中找key为SpringApplicationRunListener对应类,并实例化。
1.2.3 步骤3.1.2:
代码 public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
@Override
@SuppressWarnings("deprecation")
public void starting() {
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}

分析 
:发布ApplicationStartedEvent事件。

1.2.4 步骤3.1.3:
代码 private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// ⑴. 得到环境对象ConfigurableEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// ⑵. 并配置环境信息;对listeners初始化环境属性
configureEnvironment(environment, applicationArguments.getSourceArgs());
// ⑶. 发布ApplicationEnvironmentPreparedEvent事件。
listeners.environmentPrepared(environment);
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
return environment;
}

分析 
⑴. 得到环境对象ConfigurableEnvironment 
⑵. 并配置环境信息;对listeners初始化环境属性。 
⑶. 发布ApplicationEnvironmentPreparedEvent事件。

步骤3.1.4:
分析
创建ApplicationContext对象 ,其中在实例化ApplicationContext子类
AnnotationConfigApplicationContext时,如代码: public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

会创建AnnotatedBeanDefinitionReader对象检测是否需要将一下对象放到Spring上下文中

// 用户配置Configuration注解,实现了BeanDefinitionRegistryPostProcessor接口
ConfigurationClassPostProcessor
// 用于配置Autowired注解,实现了MergedBeanDefinitionPostProcessor接口
AutowiredAnnotationBeanPostProcessor
// 用于配置Required注解,实现了MergedBeanDefinitionPostProcessor接口
RequiredAnnotationBeanPostProcessor
// 用于配置JSR-250注解,实现了InstantiationAwareBeanPostProcessor接口
CommonAnnotationBeanPostProcessor
// 用于配置JPA注解
PersistenceAnnotationBeanPostProcessor
// 用于配置EventListener注解,实现了SmartInitializingSingleton接口
EventListenerMethodProcessor
// EventListener工厂
DefaultEventListenerFactory
步骤3.1.5:
代码 private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// ⑴.对ApplicationContext设置环境变量;
context.setEnvironment(environment);
// ⑵.配置属性ResourceLoader和ClassLoader属性;
postProcessApplicationContext(context);
// ⑶.循环初始化继承了
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
} // Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
} // Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}

分析: 
⑴.对ApplicationContext设置环境变量; 
⑵.配置属性ResourceLoader和ClassLoader属性; 
⑶.调用步骤1查询出来ApplicationContextInitializer子类,循环调用initialize()方法。

@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}

⑷.发布ApplicationPreparedEvent事件。

步骤3.1.6
代码: @Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// ⑴.准备刷新的上下文环境
prepareRefresh(); // ⑵.初始化BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // ⑶.对BeanFactory进行各种功能填充
prepareBeanFactory(beanFactory); try {
// ⑷.子类覆盖方法做额外的处理
postProcessBeanFactory(beanFactory); // ⑸.激活各种BeanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory); // ⑹.注册拦截Bean创建的Bean处理,这里只是注册,真正调用是再拿去Bean的时候
registerBeanPostProcessors(beanFactory); // ⑺.为上下文初始化Message源,即不同语言的消息体,国际化处理
initMessageSource(); // ⑻.初始化应用消息广播器,并放到applicationEventMulticaster bean中
initApplicationEventMulticaster(); // ⑼.留给子类来初始化其他bean
onRefresh(); // ⑽.在所有注册的bean中查找Listener bean,注册到消息广播中
registerListeners(); // ⑾.初始化剩下的单实例(非惰性)
finishBeanFactoryInitialization(beanFactory); // ⑿.完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

分析:

⑴.准备刷新的上下文环境
⑵.初始化BeanFactory
⑶.对BeanFactory进行各种功能填充
⑷.子类覆盖方法做额外的处理
⑸.激活各种BeanFactory处理器
⑹.注册拦截Bean创建的Bean处理,这里只是注册,真正调用是再拿去Bean的时候
⑺.为上下文初始化Message源,即不同语言的消息体,国际化处理
⑻.初始化应用消息广播器,并放到applicationEventMulticaster bean中
⑼.留给子类来初始化其他bean
⑽.在所有注册的bean中查找Listener bean,注册到消息广播中
⑾.初始化剩下的单实例(非惰性)
⑿.完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人

总结:

Spring 是一个“引擎” 
Spring MVC 是基于 Spring 的一个 MVC 框架 
Spring Boot 是基于 Spring4 的条件注册的一套快速开发整合包 

Spring 最初利用“工厂模式”( DI )和“代理模式”( AOP )解耦应用组件,并构建了一些列功能组件。大家觉得挺好用,于是按照 MVC 框架模式,(用Spring 解耦的组件)搞了一个MVC用来开发 web 应用也就是( SpringMVC )。然后有发现每次开发都要搞很多依赖,写很多样板代码很麻烦,于是搞了一些懒人整合包( starter ),这套就是 Spring Boot 。  
spring 框架有超多的延伸产品例如 boot security jpa etc... 但它的基础就是 spring 的 ioc 和 aop ioc 提供了依赖注入的容器 aop 解决了面向横切面的编程 然后在此两者的基础上实现了其他延伸产品的高级功能 Spring MVC 呢是基于 Servlet 的一个 MVC 框架 主要解决 WEB 开发的问题 因为 Spring 的配置太复杂了 各种 XML JavaConfig hin 麻烦 于是懒人改变世界推出了 Spring boot 约定优于配置 简化了 spring 的配置流程 简单谈下自己的理解   以上来自度娘,感觉和自己的理解相当。直接拿来用,占个坑。以后完善。

springApplication可以读取不同种类的源文件:

  • 类- java类由AnnotatedBeanDefinitionReader加载。
  • Resource - xml资源文件由XmlBeanDefinitionReader读取, 或者groovy脚本由GroovyBeanDefinitionReader读取
  • Package - java包文件由ClassPathBeanDefinitionScanner扫描读取。
  • CharSequence - 字符序列可以是类名、资源文件、包名,根据不同方式加载。如果一个字符序列不可以解析程序到类,也不可以解析到资源文件,那么就认为它是一个包。

SpringBoot启动过程原理的更多相关文章

  1. SpringBoot启动过程原理(转)

    1.1 Springboot启动: @SpringBootApplication public class ServerApplication { public static void main(St ...

  2. Spring Boot 学习笔记一(SpringBoot启动过程)

    SpringBoot启动 Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法. 在main方法 ...

  3. Tomcat启动过程原理详解 -- 非常的报错:涉及了2个web.xml等文件的加载流程

    Tomcat启动过程原理详解 发表于: Tomcat, Web Server, 旧文存档 | 作者: 谋万世全局者 标签: Tomcat,原理,启动过程,详解 基于Java的Web 应用程序是 ser ...

  4. SpringBoot启动流程原理解析(二)

    在上一章我们分析了SpingBoot启动流程中实例化SpingApplication的过程. return new SpringApplication(primarySources).run(args ...

  5. (四)SpringBoot启动过程的分析-预处理ApplicationContext

    -- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇(三)SpringBoot启动过程的分析-创建应用程序上下文,本文将分析上下文创建完毕之后的下一步操作:预处理上下文容器. 预处理上下文 ...

  6. (三)SpringBoot启动过程的分析-创建应用程序上下文

    -- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇(二)SpringBoot启动过程的分析-环境信息准备,本文将分析环境准备完毕之后的下一步操作:ApplicationContext的创 ...

  7. (一)SpringBoot启动过程的分析-启动流程概览

    -- 以下内容均基于2.1.8.RELEASE版本 通过粗粒度的分析SpringBoot启动过程中执行的主要操作,可以很容易划分它的大流程,每个流程只关注重要操作为后续深入学习建立一个大纲. 官方示例 ...

  8. (五)SpringBoot启动过程的分析-刷新ApplicationContext

    -- 以下内容均基于2.1.8.RELEASE版本 紧接着上一篇[(四)SpringBoot启动过程的分析-预处理ApplicationContext] (https://www.cnblogs.co ...

  9. springboot启动过程(1)-初始化

    1   springboot启动时,只需要调用一个类前面加了@SpringBootApplication的main函数,执行SpringApplication.run(DemoApplication. ...

随机推荐

  1. mac本地搭建wordpress

    1 下载安装最新的xampp 2 安装完成后,使用下面的命令开始运行 XAMPP.在终端下以系统管理员 root 的身份登录 管理员root身份登录 sudo su 使用命令启动XAMPP /Appl ...

  2. VS 一键调用 SVN Blame

    在Windows上做项目开发的时候,常常需要调用SVN Blame去追溯一个文件的编辑历史,但是这个常见的需求往往需要很繁琐的步骤.首先需要打开文件所在文件夹,然后右键,在一长排上下文菜单中准确地选中 ...

  3. CDN新应用和客户

    目前的CDN配置服务主要应用于证券.金融保险.ISP.ICP.网上交易.门户网站.大中型公司.网络教学等领域.另外在行业专网.互联网中都可以用到,甚至可以对局域网进行网络优化.利用CDN,这些网站无需 ...

  4. Unity 3d导入3dMax模型 产生若干问题

    Unity 3d导入3dMax模型 会产生若干问题,按照官方 的说明,将max 模型导成fbx文件 导入untiy似乎也不能解决 1.x轴向偏转3dmax模型导入后自动有一个x轴270度的偏转,巧合的 ...

  5. mui 页面跳转

    1.初始化时创建子页面 mui.init({ subpages: [{ url: your - subpage - url, //子页面HTML地址,支持本地地址和网络地址 id: your - su ...

  6. 08-hibernate注解-总结

    直接贴过来了: 1, 2,

  7. JS遍历数组类型元素

    已停供用户不能再次停供,之前没太处理过多维数组的遍历,趁这个机会回顾一下js数组遍历 可以看出rows 获取了两条数据,为二维数组类型 方法 function batchTgWin() { var r ...

  8. Linux命令-网络命令:mail

    root用户发送邮件 mail wangyunpeng 给wangyunpeng发送邮件,wangyunpeng不在线也可以收到发送的邮件 wangyunpeng用户接收邮件 mail 接收邮件 he ...

  9. 探寻BTree 索引对sql 优化影响

    从一道题開始分析: 如果某个表有一个联合索引(c1,c2,c3,c4)一下--仅仅能使用该联合索引的c1,c2,c3部分 A where c1=x and c2=x and c4>x and c ...

  10. sql server中Join有几种

    JOIN: 如果表中有至少一个匹配,则返回行 (也就是 inner join)LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有 ...