是什么

Spring Boot基于Spring框架之上的一个微服务架构开发框架
大大简化了Spring的开发。因为Spring Boot提供了大量的自动配置。而且它是基于Java配置方式的开发(全注解)
Spring Boot与集成了许多第三方框架并进行了最小化自动配置
Spring Boot和Spring Cloud关系:Spring Cloud的开发需要用Spring Boot,反之不一定
官方介绍
Spring Boot使创建独立的、生产级的基于Spring的应用程序变得很容易,您可以“直接运行”这些应用程序。
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".
我们对Spring平台和第三方库有自己的看法,这样您就可以轻松入门了。大多数Spring启动应用程序只需要很少的Spring配置。
We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need very little Spring configuration.

特点

创建独立的Spring应用程序
Create stand-alone Spring applications
直接嵌入Tomcat、Jetty或Undertow(不需要部署WAR文件)
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
提供独到的起始依赖去简化配置
Provide opinionated 'starter' dependencies to simplify your build configuration
在可能的情况下自动配置Spring和第三方库
Automatically configure Spring and 3rd party libraries whenever possible
提供可用于生产的特性,如度量标准、健康状况检查和外部化配置
Provide production-ready features such as metrics, health checks and externalized configuration
完全不需要代码生成,也不需要XML配置  去XML化
Absolutely no code generation and no requirement for XML configuration

启动流程

  • 创建 SpringApplication

    •   保存一些信息。
    •   判定当前应用的类型。ClassUtils。Servlet
    •   bootstrappers:初始启动引导器(List):去spring.factories文件中找 org.springframework.boot.Bootstrapper
    •   找 ApplicationContextInitializer 应用初始化器,去spring.factories找 ApplicationContextInitializer
      •     List<ApplicationContextInitializer<?>> initializers
    •   找 ApplicationListener  ,应用监听器。去spring.factories找 ApplicationListener
      •     List<ApplicationListener<?>> listeners
  • 运行 SpringApplication
    •   StopWatch
    •   记录应用的启动时间
    •   创建引导上下文(Context环境)createBootstrapContext()
      •     获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置
    •   让当前应用进入headless模式。java.awt.headless
    •   获取所有 RunListener(运行监听器)【为了方便所有Listener进行事件感知】
      •     getSpringFactoriesInstances 去spring.factories找 SpringApplicationRunListener.
    •   遍历 SpringApplicationRunListener 调用 starting 方法;
      •     相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。
    •   保存命令行参数;ApplicationArguments
    •   准备环境 prepareEnvironment();
      •     返回或者创建基础环境信息对象。StandardServletEnvironment
      •     配置环境信息对象。
        •       读取所有的配置源的配置属性值。
      •     绑定环境信息
      •     监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成
    •   创建IOC容器(createApplicationContext())
      •     根据项目类型(Servlet)创建容器,
      •     当前会创建 AnnotationConfigServletWebServerApplicationContext
    •   准备ApplicationContext IOC容器的基本信息  prepareContext()
      •     保存环境信息
      •     IOC容器的后置处理流程。
      •     应用初始化器;applyInitializers;
        •       遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对ioc容器进行初始化扩展功能
        •       遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器contextPrepared
      •     所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoaded;
    •   刷新IOC容器。refreshContext
      •     创建容器中的所有组件(Spring注解)
    •   容器刷新完成后工作?afterRefresh
    •   所有监听 器 调用 listeners.started(context); 通知所有的监听器 started
    •   调用所有runners;callRunners()
      •     获取容器中的 ApplicationRunner
      •     获取容器中的  CommandLineRunner
      •     合并所有runner并且按照@Order进行排序
      •     遍历所有的runner。调用 run 方法
    •   如果以上有异常,
      •     调用Listener 的 failed
    •   调用所有监听器的 running 方法  listeners.running(context); 通知所有的监听器 running
    •   running如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failed

启动类

1 @SpringBootApplication
2 @EnableAutoConfiguration(exclude = HibernateJpaAutoConfiguration.class)
3 @EnableScheduling
4 public class Application {
5
6 public static void main(String[] args) {
7 SpringApplication.run(Application.class, args);
8 }

SpringApplication.run方法

引导了springboot在各个时机执行哪些方法,关键组件什么时候加载和运行

new sprngApplication()创建

public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
} public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
//断言启动类不为空
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//应用类型判断,servlet还是react
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

run运行

/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
//启停监听器
StopWatch stopWatch = new StopWatch();
//记录启动时间
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//当前应用进入headless自力更生模式
configureHeadlessProperty();
//获取所有运行时监听器 通过SpringFactoryInstance去spring.factories下找SpringApplicationRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
//保存传过来的args参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备环境信息 包括加载外部配置源 调用listener.envirementPrepared()通知监听器环境准备完
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//配置需要忽略的信息
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//创建IOC容器 根据当前项目类型 servlet or reactive 这里是servlet
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备IOC容器信息
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新IOC容器 创建容器中的所有组件
refreshContext(context);
//刷新后的处理 暂时没干任何工作
afterRefresh(context, applicationArguments);
//监听启动完成花费多少时间
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//通知监听器项目已经启动
listeners.started(context);
//调用所有能遍历到的runner,获取ApplicationRunner和CommandLineRuner 执行它们的run方法
callRunners(context, applicationArguments);
}
//如果有异常,调用listeners.failed 容器创建失败
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
} try {
//调用listener的running方法,通知监听器程序已经进入runnig状态
listeners.running(context);
}
catch (Throwable ex) {
//如果有异常,调用listeners.failed 容器创建失败
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
//返回整个IOC容器
return context;
}

准备IOC容器信息

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//保存基础环境
context.setEnvironment(environment);
//IOC容器的后置处理
postProcessApplicationContext(context);
//应用之前的那些初始化器,对IOC容器记性初始化扩展
applyInitializers(context);
//通知监听器上下文准备完成
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}

刷新IOC容器 创建容器中的所有组件

private void refreshContext(ConfigurableApplicationContext context) {
//spring核心源码 刷新底层的ApplicationContext。
refresh((ApplicationContext) context);
if (this.registerShutdownHook) {
try {
//向JVM运行时注册一个关闭钩子,在JVM关闭时关闭这个上下文
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
} /**
* Refresh the underlying {@link ApplicationContext}.
* @param applicationContext the application context to refresh
*/
protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}
/**
*spring经典的整个初始化过程
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // Check for listener beans and register them.
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
//实例化所有剩余的非延迟加载的单例组件
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
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();
}
}
}

自动装配原理

引入

示例:rocketmq的自动配置
要生效,就要满足两个@conditional族注解

@springbootApplication注解中自动配置相关

@springbootApplication中有一个@EnableAutoConfiguration
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{} ======================

@EnableAutoConfiguration中有@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})

@AutoConfigurationPackage进行组件注册,@Import(AutoConfigurationImportSelector.class)导入的AutoConfigurationImportSelector组件调用loadSpringFactories()方法,利用工厂加载,扫描当前系统里面所有META-INF/spring.factories位置的文件,得到所有自动配置组件,

但是会按需配置,这个是通过@Condition注解族实现的,比如@ConditionalOnMissingBean指定以用户自己配置的优先

@AutoConfigurationPackage

@Import(AutoConfigurationPackages.Registrar.class)  //给容器中导入一个组件
public @interface AutoConfigurationPackage {} //利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来?MainApplication 所在包下。

@Import(AutoConfigurationImportSelector.class)

1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
4、从META-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfigurati

按需开启自动配置

虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration 按照条件装配规则(@Conditional),最终会按需配置。

可以修改默认配置

        @Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先 @ConditionalOnMissingBean

总结

  • SpringBoot先加载所有的自动配置类  xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
  • 生效的配置类就会给容器中装配很多组件
  • 只要容器中有这些组件,相当于这些功能就有了
  • 定制化配置
  • 用户直接自己@Bean替换底层的组件
  • 用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration ---> 组件  ---> xxxxProperties里面拿值  ----> application.properties
 

SpringBoot启动流程与自动装配的更多相关文章

  1. SpringBoot启动代码和自动装配源码分析

    ​ 随着互联网的快速发展,各种组件层出不穷,需要框架集成的组件越来越多.每一种组件与Spring容器整合需要实现相关代码.SpringMVC框架配置由于太过于繁琐和依赖XML文件:为了方便快速集成第三 ...

  2. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  3. SpringBoot启动流程解析

    写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...

  4. SpringBoot启动流程分析(六):IoC容器依赖注入

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  5. SpringBoot启动流程分析(一):SpringApplication类初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  6. SpringBoot启动流程分析(二):SpringApplication的run方法

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  7. SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  8. SpringBoot启动流程分析(四):IoC容器的初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  9. SpringBoot源码学习3——SpringBoot启动流程

    系列文章目录和关于我 一丶前言 在 <SpringBoot源码学习1--SpringBoot自动装配源码解析+Spring如何处理配置类的>中我们学习了SpringBoot自动装配如何实现 ...

  10. SpringBoot启动流程及其原理

    Spring Boot.Spring MVC 和 Spring 有什么区别? 分别描述各自的特征: Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等:但他们的 ...

随机推荐

  1. js替换字符中指定所有字符

    //js \n全部替换<br/> function tranceBr(str) { return str.replace(/\n/g, '<br/>'); }

  2. 一文吃透 Go 内置 RPC 原理

    hello 大家好呀,我是小楼,这是系列文<Go底层原理剖析>的第三篇,依旧分析 Http 模块.我们今天来看 Go内置的 RPC.说起 RPC 大家想到的一般是框架,Go 作为编程语言竟 ...

  3. linux配置爬虫环境

    #宝塔面板安装python3 #安装依赖包 yum -y groupinstall "Development tools" yum -y install zlib-devel bz ...

  4. ASP判断一个字符是否为汉字的两种方法

    有的时候我们要求用户一定要输入汉字的信息,比如姓名和地址.那么,如何判断一个字符是不是汉字呢?其实在asp中至少有两种方法: 一.直接将某字符用asc转为ascii码,如果是英文,他应该是0-127的 ...

  5. label 与input其中input的 id与name

    <div> <label for="myfile">新头像 {% load static %} <img src="{% static 'i ...

  6. Git提交代码报错husky > pre-commit,

    拉取了新项目以后,git突然不能用了   报husky > pre-commit, 解决办法:进入你的项目显示隐藏git文件  进入git文件   找到  hooks / pre-commit  ...

  7. python笔记--在文件进行输出

    将print的内容输出到文件中 1 #将数据输出到文件中 2 fp=open('E:/text1.txt','a+') 3 print('hello word',file=fp) 4 fp.close ...

  8. vue中如何在子组件添加类似于watch属性监听父组件数据,数据变化时子组件做出相应的动作

    首先:我们需要在父组件中标签中定义一个 ref="parentObjVue" 其次:我们在子组件中,通过  var tmp=this.$refs.parentObjVue找到父组件 ...

  9. .net core使用 ELK

    一 Linux 下安装部署 第一种方法:docker-compose 安装方式 1.1 创建 docker-compose.yml 文件 version: '3.1' services: elasti ...

  10. C++ MFC学习 (五)

    Edit Control 当不设置多行时,敲击回车会关闭对话框 1 void CMFC_Demo4Dlg::OnBnClickedButton2() 2 { 3 // TODO: 在此添加控件通知处理 ...