SpringBoot核心运行原理

Spring Boot 最核心的功能就是自动配置,第 1 章中我们已经提到,功能的实现都是基于“约定优于配置”的原则。那么 Spring Boot 是如何约定,又是如何实现自动配置功能的呢?

本章会带领大家通过源码学习 Spring Boot 的核心运作原理,内容涉及自动配置的运作原理、核心功能模块、核心注解以及使用到的核心源代码分析。

核心运行原理

使用 Spring Boot 时,我们只需引|入对应的 Starters, Spring Boot 启动时便会自动加载相关依赖,配置相应的初始化参数,以最快捷、简单的形式对第三方软件进行集成,这便是 SpringBoot 的自动配置功能。我们先从整体上看一下 Spring Boot 实现该运作机制涉及的核心部分,如图 2-1 所示。

图 2-1 描述了 Spring Boot 自动配置功能运作过程中涉及的几个核心功能及其相互之间的关系包括@EnableAutoConfiguration、spring.factories、各组件对应的 AutoConfiguration 类、@Conditional 注解以及各种 Starters。

可以用一句话来描述整个过程:Spring Boot 通过@EnableAutoConfiguration 注解开启自动配置,加载 spring.factories 中注册的各种 AutoConfiguration 类,当某个 AutoConfiguration类满足其注解@Conditional 指定的生效条件(Starters 提供的依赖、配置或 Spring 容器中是否存在某个 Bean 等)时,实例化该 AutoConfiguration 类中定义的 Bean(组件等),并注入 Spring 容器,就可以完成依赖框架的自动配置。

我们先从概念及功能上了解一下图 2-1 所示部分的作用及相互关系,在后面章节中会针对每个功能及组件进行源代码级别的讲解。

·@EnableAutoConfiguration:该注解由组合注解@SpringBootApplication 引入,完成自动配置开启,扫描各个jar包下的spring.factories文件,并加载文件中注册的AutoConfiguration类等。

·spring.factories:配置文件,位于 jar 包的 META-INF 目录下,按照指定格式注册了自动配置的 AutoConfiguration 类。spring.factories 也可以包含其他类型待注册的类。该配置文件不仅存在于 Spring Boot 项目中,也可以存在于自定义的自动配置(或 Starter)项目中。

·AutoConfiguration 类:自动配置类,代表了 Spring Boot 中一类以 XXAutoConfiguration命名的自动配置类。其中定义了三方组件集成 Spring 所需初始化的 Bean 和条件。

·@Conditional:条件注解及其衍生注解,在 AutoConfiguration 类上使用,当满足该条件注解时才会实例化 AutoConfiguration 类。

·Starters:三方组件的依赖及配置,Spring Boot 已经预置的组件。Spring Boot 默认的Starters 项目往往只包含了一个 pom 依赖的项目。如果是自定义的 starter,该项目还需包含 spring.factories 文件、AutoConfiguration 类和其他配置类。

以上在概念层面介绍了 Spring Boot 自动配置的整体流程和基本运作原理,下面将会详细介绍这几个核心部分的组成结构及源代码。

运作原理源码解析 Z@EnableAutoConfiguration

@EnableAutoConfiguration 是开启自动配置的注解,在创建的 SpringBoot 项目中并不能直接看到此注解,它是由组合注解@SpringBootApplication 引入的。下面我们先来了解一下 入口类和@SpringBootApplication 注解的功能,然后再深入了解@EnableAutoConfiguration注解的构成与作用。

入口类和@SpringBootApplication 注解

Spring Boot 项目创建完成会默认生成-个*Application 的入口类。 在默认情况下,无论是通过 IDEA 还是通过官方创建基于 Maven 的 Spring Boo 项目,入口类的命名规则都是artifactld+Application。通过该类的 main 方法即可启动 Spring Boot 项目,代码如下。

@SpringBootApplication
public class SpringLearnApplication {
public static void main(String[] args) {
SpringApplication. run(DemoApplication. class, args);
}
}

这里的 main 方法并无特别之处,就是一一个标准的 Java 应用的 main 方法,用于启动 SpringBoot 项目的入口。在默认情况下,按照上述规则命名并包含 main 方法的类称为入口类。

在 Spring Boot 入口类(除单元测试外)中,唯一的一个注解就是@SpringBootApp-lication。

它是 Spring Boot 项目的核心注解,用于开启自动配置,准确说是通过该注解内组合的@EnableAutoConfiguration 开启了自动配置。

@SpringBootApplication 部分源代码如下。

@Target(ElementType . TYPE)
@Retent ion(Retent ionPolicy . RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfi guration
@ComponentScan( excludeFilters = {
@Filter(type = FilterType .CUSTOM, classes = TypeExcludeFilter. class),
@Filter(type = FilterType. CUSTOM,
classes = AutoConf igurationExcludeFilter . class) })
public @interface SpringBootApplication {
//排除指定自动配置类
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
//排除指定自动配置类名
@AliasFor( annotation = EnableAutoConfiguration. class)
String[] excludeName() default {
//指定扫描的基础包,激活炷解组件的初始化
@AliasFor( annotation = ComponentScan. class, attribute = "basePackages")
String[] scanBasePackages() default {};
//指定扫描的类,用于初始化
@AliasFor( annotation = ComponentScan. class, attribute = "basePackageClass
Class<?>[] scanBasePackageClasses() default {};
//指定是否代理@Bean 方法以强制执行 bean 的生命周期行为
@AliasFor( annotation = Configuration.class)
boolean proxyBeanMethods() default true ; }

通过源代码可以看出,该注解提供了以下成员属性(注解中的成员变量以方法的形式体现)。

exclude:根据类(Class) 排除指定的自动配置,该成员属性覆盖了@SpringBoot-Application中组合的@ EnableAutoConfiguration 中定义的 exclude 成员属性。

excludeName :根据类名排除指定的自动配置,覆盖了@ EnableAutoConfiguration 中的excludeName 的成员属性。

:scanBasePackages:指定扫描的基础 package,用于激活@Component 等注解类的初始化。

scanBasePackageClasses:扫描指定的类,用于组件的初始化。

:proxyBeanMethods:指定是否代理@ Bean 方法以强制执行 bean 的生命周期行为。此功能需要通过运行时生成 CGLIB 子类来实现方法拦截。该子类有一定的限制,比如配置类及其方法不允许声明为 final 等。

proxyBeanMethods 的默认值为 true,允许配置类中进行 inter-beanreferences (bean 之 间的引用)以及对该配置的@Bean 方法的外部调用。如果@Bean 方法都是自包含的,并且仅提供了容器使用的普通工程方法的功能,则可设置为 false,避免处理 CGLIB 子类。SpringBoot 2.2 版本上市后新增该成员属性,后面章节涉及的自动配置类中基本都会用到proxyBeanMethods,一 般情况下都配置为 false。

通过以上源代码我们会发现,Spring Boot 中大量使用了@AliasFor 注解,该注解用于桥接到其他注解,该注解的属性中指定了所桥接的注解类。如果点进去查看,会发现@SpringBootApplication 定 义的属性在其他注解中已经定义过了。之所以使用@AliasFor注解并重新在@SpringBootApplication 中定义,更多是为了减少用户使用多注解带来的麻烦。

@SpringBootApplication

注 解 中 组 合 了 @SpringBootConfiguration 、@EnableAutoConfiguration 和@ComponentScan。因此,在实践过程中也可以使用这 3 个注解来替代@SpringBootApplication。

在 Spring Boot 早期版本中并没有@SpringBootConfiguration 注解,版本升级后新增了@SpringBootConfiguration 并在其内组合了@Configuration。

@EnableAutoConfiguration 注解组合了@AutoConfigurationPackage.我们忽略掉一些基础注解和元注解, @SpringBootApplication 注解的组合结构可以参考图2-2。

在图2-2中,@SpringBootApplication除 了组合元注解之外,其核心作用还包括:激活SpringBoot 自 动 配 置 的 @EnableAutoConfiguration 、 激 活 @Component 扫 描 的@ComponentScan、激活配置类的@Configuration。

其中@ComponentScan 注解和@Configuration 注解在日常使用 Spring 时经常用到,也非常 基 础 , 大 家应该都有一些了 解 , 这 里 就 不 再 赘 述 了 。 下 面 详 细 介 绍@EnableAuto-Configuration 的功能。

注解@EnableAutoConfiguration功能解析

在未使用 Spring Boot 的情况下,Bean 的生命周期由 Spring 来管理,然而 Spring 无法自动配置@Configuration 注解的类。而 Spring Boot 的核心功能之- 就是根据约定自动管理该注解标注的类。用来实现该功能的组件之-便是@EnableAutoConfiguration 注解。

@EnableAutoConfiguration 位 于 spring-boot autoconfigure 包 内 , 当 使 用@SpringBootApplication 注解时,@EnableAutoConfiguration 注 解会自动生效。

@EnableAutoConfiguration 的主要功能是启动 Spring 应用程序上下文时进行自动配置,它会尝试猜测并配置项目可能需要的 Bean。自动配置通常是基于项目 classpath 中引入的类和已定义的 Bean 来实现的。在此过程中,被自动配置的组件来自项目自身和项目依赖的 jar包中。

举 个 例 子 : 如 果 将 tomcat-embedded.jar 添 加 到 classpath 下 , 那 么@EnableAutoConfiguration 会认为你准备用
TomcatServletWebServerFactory 类,并帮你初始化相关配置。与此同时,如果自定义了基于 ServletWebServerFactory 的 Bean ,那么@EnableAutoConfiguration 将不会进行 TomcatServletWebServerFactory 类的初始化。这一系列的操作判断都由 Spring Boot 来完成。

下面我们来看一下@EnableAutoConfiguration 注解的源码。

@Target(ElementType . TYPE)
@Retention( RetentionPolicy . RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConf igurat ionImportSelector. class)
public @interface EnableAutoConfiguration {
//用来餐盖配置开启/关闭自动配置的功能
String ENABLED. OVERRIDE_ PROPERTY = "spring. boot . enableautoconf iguration" ;
//根据类(Class) 排除指定的自动配置
Class<?>[] exclude() default {};
//根据类名排除指定的自动配置
String[] excludeName() default {};
}

@EnableAutoConfiguration 注解提供了一-个常量和两个成员参数的定义。

ENABLED OVERRIDE PROPERTY:用来覆盖开启/关闭自动配置的功能。

-exclude:根据类(Class) 排除指定的自动配置。

excludeName:根据类名排除指定的自动配置。

正如上文所说,@EnableAutoConfiguration 会猜 测你需要使用的 Bean,但如果在实战中你并不需要它预置初始化的 Bean,可通过该注解的 exclude 或 excludeName 参数进行有针对性的排除。比如,当不需要数据库的自动配置时,可通过以下两种方式让其自动配置失效。

//通过@SpringBootAppl ication 排除 DataSourceAutoConfiguration
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class SpringLearnApplication {
}
或:
//通过@Enabl eAutoConfiguration 排除 DataSourceAutoConfiguration
@Configuration
@EnableAutoConfiguration( exclude = DataSourceAutoConfiguration. class)
public class DemoConfiguration {
}

需要注意的是,被@EnableAutoConfiguration 注 解的类所在 package 还具有特定的意义,通常会被作为扫描注解@Entity 的根路径。这也是在使用@SpringBootApplication 注解时需要将被注解的类放在顶级 package 下的原因,如果放在较低层级,它所在 package 的同级或上级中的类就无法被扫描到。

而 对 于 入 口 类 和 其 main 方 法 来 说 , 并 不 依 赖 @SpringBootApplication 注 解 或@EnableAuto-Configuration 注解,也就是说该注解可以使用在其他类上,而非入口类上。

本文给大家讲解的内容是SpringBoot核心运行原理和运作原理源码解析

  1. 下篇文章给大家讲解的是AutoConfigurationlmportSelector源码解析;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

深入解析SpringBoot核心运行原理和运作原理源码相关推荐

  1. SpringBoot原理-SpringBoot核心运行原理

    导语   Spring Boot最为核心的功能就是自动配置,所有功能的实现都是基于"约定优于配置"的原则,但是Spring Boot是如何实现自动配置的功能的,下面就通过源码学习S ...

  2. Java线性池的使用方式以及核心运行原理

    Java线性池的使用方式以及核心运行原理 一.为什么需要线性池? 二.线性池的处理流程 三.线程池的使用(ThreadPoolExecutor) 四.线程池的注意事项 一.为什么需要线性池? java ...

  3. PCL 实现 SAC_IA 算法原理源码解析

    PCL 实现 SAC_IA 算法原理源码解析 采样一致性算法(SAC_IA)用于点云粗配准中,配准效果还不错,PCL 中也实现了该算法,本文深入 PCL 源码,学习一下 SAC_IA 算法在 PCL ...

  4. vue双向绑定原理源码解析

    当我们学习angular或者vue的时候,其双向绑定为我们开发带来了诸多便捷,今天我们就来分析一下vue双向绑定的原理. 简易vue源码地址:https://github.com/maxlove123 ...

  5. Mybatis运行原理源码分析

    运行中涉及到的类以及源码剖析 1.1 Resources:MyBatis 中 IO 流的工具类 Mybatis运行的第一步首先需要加载全局配置文件(参照Mybatis官网上的例子,就是mybatis- ...

  6. Java多线程系列(三):Java线程池的使用方式,及核心运行原理

    之前谈过多线程相关的4种常用Java线程锁的特点,性能比较.使用场景,今天主要分享线程池相关的内容,这些都是属于Java面试的必考点. 为什么需要线程池 java中为了提高并发度,可以使用多线程共同执 ...

  7. 深入SpringBoot核心注解原理

    源码分享:Javaweb练手项目下载 今天跟大家来探讨下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot为什么不需要XML,达到零配 ...

  8. linkedblockingqueue使用_Java线程池的使用方式,核心运行原理、以及注意事项

    为什么需要线程池 java中为了提高并发度,可以使用多线程共同执行,但是如果有大量线程短时间之内被创建和销毁,会占用大量的系统时间,影响系统效率. 为了解决上面的问题,java中引入了线程池,可以使创 ...

  9. 深度解析,单片机运行原理,你知道吗?

    同名回复"入门资料"获取单片机入门到高级进阶教程 单片机是将中央处理单元(CPU).储存器.输入输出集成在一片芯片上,可以说单片机就是一台微型计算机,只是和我们平常使用的计算机相比 ...

最新文章

  1. 【深度学习理论】(3) 激活函数
  2. pytorch图像和张量的相互转换_如何加载图像并将其转换为PyTorch的适当张量?
  3. c# 操作IIS应用程序池
  4. 视图自己定义旋转动画 相似百度音乐
  5. 美英澳联合发布2020-2021期间遭利用最多的 Top 30漏洞
  6. paip.提升用户检验--------取回密码-忘记密码提醒
  7. json-server安装报错问题
  8. 人工智能--一种现代的方法(知识点总结第一章)
  9. 组合体视图的画图步骤_工程制图 组合体
  10. 2.5 浅层/深层神经网络
  11. 波浪谱 matlab画,matlab窄带随机过程
  12. 信息检索导论要点整理
  13. ES9023音频解码芯片的工作原理
  14. android项目屏幕适配的解决方法
  15. ERP打印入库单(四十)
  16. 不只是A/B测试:多臂老虎机赌徒实验
  17. [安全攻防进阶篇] 二.如何学好逆向分析、逆向路线推荐及吕布传游戏逆向案例
  18. java计算机毕业设计小型酒店管理系统源码+系统+数据库+lw文档+mybatis+运行部署
  19. mapreduce 中文版 中文翻译
  20. 有关防爆知识(防爆标识格式解释)

热门文章

  1. vue-cli初次搭建项目脚手架的过程(前后端分离第一步)
  2. bilibili手机端追剧在哪里?
  3. Java适配器模式(adapter)
  4. Linux CentOS中按tab键不能自动补全解决办法
  5. 基础算法-Xgboost
  6. javaSE从入门到精通的二十万字总结(二)
  7. 【专题地图编制设计与制作】
  8. 交换两个变量值的几种方法-C语言初学者
  9. week3--CSS基础 盒子模型 选择器
  10. 多进程(Multiprocessing)