最近这两年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. java实现归并排序算法

    归并排序算法思想:分而治之(divide - conquer);每个递归过程涉及三个步骤第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素.第二, 治理: ...

  2. svn: warning: xxxx is already under version control

    svn stat  查看当前目录下svn状态 svn remove xxxx svn add xxx svn ci -m "注释"

  3. 分享10个超实用的jQuery代码片段

    来源:GBin1.com jQuery以其强大的功能和简单的使用成为了前端开发者最喜欢的JS类库,在这里我们分享一组实用的jQuery代码片段,希望大家喜欢! jQuery平滑回到顶端效果 $(doc ...

  4. .Net Framemwork 之 值类型和引用类型的存储

    C#把数据类型分为两种:值类型 和 引用类型.值类型存储在堆栈中,而引用类型存储在托管堆上. 一.值类型和引用类型变量的存储 首先,变量是存储信息的基本单元,而对于计算机内部来说,变量就相当于一块内存 ...

  5. js中,{}初始化数据类型object;for in 的用法;delete的用法

    var choices = {}; //此数据表示的是:object{} for(var i=0;i<10;i++){ choices[i+1] = [data[i].testPlan,test ...

  6. JavaScript 中的string 方法

    创建string的方法 var str ="abc"; var str = new String("abc"); var str = String(" ...

  7. 在DATASET中要是想添加进另一个表怎么办?

    问:sql="select * from banzhu_manage ";adapter=new SqlDataAdapter(sql,banzhu_conn);adapter.F ...

  8. vpngate 的使用

    第一次为小日本打广告.. .我仅仅想仰天大喊..玛的戈壁. .. 竟然活到这个份上了...想出去看看的往下看.. vpngate 下载: http://pan.baidu.com/s/1hq5x3Ly ...

  9. Latex中设置字体颜色

    在用Latex时,想要使用不同颜色来突出某些关键点,有以下三种方案: 1.组合red.green和blue的值合成我们想要的颜色 \usepackage{color} \textcolor[rgb]{ ...

  10. golang的各种数据格式的互相转换

    int to string import ( "strconv" ) int i = 10 str1 := strconv.Itoa(i) struct to json impor ...