Spring Boot原理剖析和源码分析

依赖管理

问题一:为什么导入dependency时不需要指定版本?

spring-boot-starter-parent依赖

org.springframework.boot

spring-boot-starter-parent

2.3.0.RELEASE

上述代码中,将spring-boot-starter-parent依赖作为Spring Boot项目的统一父项目依赖管理,并将项目版本号统一为2.3.0.RELEASE,该版本号根据实际开发需求可以修改。

org.springframework.boot

spring-boot-dependencies

2.3.0.RELEASE

继续查看spring-boot-dependencies底层源文件

5.15.12

2.7.7

1.9.80

2.12.0

1.9.5

3.16.1

4.0.6

4.0.2

2.1.4

3.1.0

1.10.10

2.8.2

4.6.1

1.5.1

1.14

......

从spring-boot-dependenices底层源文件可以看出,该文件通过标签对一些常用技术框架的依赖文件进行了统一版本号管理,如activemq、spring、tomcat等,都有与Spring Boot2.3.0.RELEASE版本相匹配的版本,这也是pom.xml引入依赖文件不需要标注依赖文件版本号的原因。

问题二:spring-boot-starter-parent伏以来启动器的主要作用是进行版本统一管理,那么项目运行依赖的jar包是从何而来?

spring-boot-starter-web

org.springframework.boot

spring-boot-starter

2.1.7.RELEASE

compile

org.springframework.boot

spring-boot-starter-json

2.1.7.RELEASE

compile

org.springframework.boot

spring-boot-starter-tomcat

2.1.7.RELEASE

compile

org.hibernate.validator

hibernate-validator

6.0.17.Final

compile

org.springframework

spring-web

5.1.9.RELEASE

compile

org.springframework

spring-webmvc

5.1.9.RELEASE

compile

从上述可以看出,spring-boot-starter-web依赖启动器的主要作用是提供web开发场景所需要的底层所有依赖。

版本由spring-boot-starter-parent统一进行管理。

image-20200526100443828.png

Spring Boot官网提供了部分场景的依赖启动器,这些依赖适用与不同的开发场景,适用时直接在pom.xml中导入即可。

但是Spring Boot官网并不是针对所有的场景的开发技术框架都提供了依赖启动器,如mybatis、druid等,但是为了充分利用Spring Boot框架的优势,mybatis、druid等技术框架团队主动与Spring Boot框架进行了整合,实现了各自的依赖启动器。mybatis-spring-boot-starter、druid-spring-boot-starter。在需要的时候直接在pom.xml文件中导入即可,但是需要自己管理版本号。

自动配置(启动流程)

概念:能够在我们添加jar包依赖时,自动为我们进行配置一下配置,我们可以不需要配置或者少量配置就能运行编写的项目。

问题:Spring Boot到底是如何进行自动配置的,都把那些组件进行了自动配置?

Spring Boot 应用启动的入口是@SpringBootApplication注解标注类的main方法,

@SpringBootApplication能够扫描Spring组件并且自动配置Spring Boot

@SpringBootApplication

public class RegistryApplication {

public static void main(String[] args) {

SpringApplication.run(RegistryApplication.class);

}

}

@SpringBootApplication注解类

// 注解的适用范围:类、接口、枚举

@Target({ElementType.TYPE})

// 注解的生命周期:运行时

@Retention(RetentionPolicy.RUNTIME)

// 标明注解可标注在javadoc中

@Documented

// 标明注解可以被子类继承

@Inherited

// 标明该类为配置类

@SpringBootConfiguration

// 启动自动配置功能

@EnableAutoConfiguration

// 包扫描器

@ComponentScan(

excludeFilters = {@Filter(

type = FilterType.CUSTOM,

classes = {TypeExcludeFilter.class}

), @Filter(

type = FilterType.CUSTOM,

classes = {AutoConfigurationExcludeFilter.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 = "basePackageClasses"

)

Class>[] scanBasePackageClasses() default {};

}

从上面可以看出,@SpringBootApplication注解主要由@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan这三个核心注解组成。

@SpringBootConfiguration注解

@SpringBootConfiguration注解表示为Spring Boot配置类

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

// 配置到IOC容器

@Configuration

public @interface SpringBootConfiguration {

}

从上述可以看出,@SpringBootConfiguration注解类主要注解为@Configuration注解,该注解由Spring框架提供,表示当前类为一个配置类,并且可以被组件扫描器扫描。

@EnableAutoConfiguration注解

@EnableAutoConfiguration注解表示为自动配置类,该注解是Spring Boot最重要的注解,也是实现自动配置的注解。

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

// 自动配置包

@AutoConfigurationPackage

// 自动配置扫描导入

@Import({AutoConfigurationImportSelector.class})

public @interface EnableAutoConfiguration {

String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

Class>[] exclude() default {};

String[] excludeName() default {};

}

从源码可以发现,@EnableAutoConfiguration注解为一个组合注解,其作用就是借助@Import注解导入特定场景需要向IOC注册的Bean,并且加载到IOC容器。@AutoConfigurationPackage就是借助@Import来搜集所有符合自动配置条件的Bean定义,并且加载到IOC容器中。

(1)@AutoConfigurationPackage

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

// 导入Registrar中注册的组件

@Import({Registrar.class})

public @interface AutoConfigurationPackage {

}

从源码可以看出,@AutoConfigurationPackage注解的功能由@Import注解实现,它是Spring框架底层注解,它的作用就是给容器导入某个组件类

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

Registrar() {

}

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

// 将主程序类所在的包以及所有子包下的组件扫描到Spring容器

AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());

}

public Set determineImports(AnnotationMetadata metadata) {

return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));

}

}

从上述可以看出,@AutoConfigurationPackage注解的主要作用就是将主程序类所在的包以及所有子包下的组件加载到IOC容器中。

因此:在定义项目包目录时,要求定义的包结构必须规范,项目主程序启动类要放在最外层的根目录位置,然后在根目录的位置内部建立子包和类进行业务开发,这样才能保证定义的类才能被组件扫描器扫描。

(2)@Import({AutoConfigurationImportSelector.class})

将 AutoConfigurationImportSelector 类导入到Spring容器中。AutoConfigurationImportSelector 可以帮助Spring容器将所有符合条件的@Configuration配置都加载到Spring Boot创建并使用的IOC容器(ApplicationContext)中。

public String[] selectImports(AnnotationMetadata annotationMetadata) {

if (!this.isEnabled(annotationMetadata)) {

return NO_IMPORTS;

} else {

// 获取自动配置的元数据,需要传入beanClassLoader这个类加载器

AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);

AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);

return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

}

}

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {

if (!this.isEnabled(annotationMetadata)) {

return EMPTY_ENTRY;

} else {

AnnotationAttributes attributes = this.getAttributes(annotationMetadata);

// 从META-INF/spring.factories配置文件中将对于的自动配置类获取到

List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

configurations = this.removeDuplicates(configurations);

Set exclusions = this.getExclusions(annotationMetadata, attributes);

this.checkExcludedClasses(configurations, exclusions);

configurations.removeAll(exclusions);

configurations = this.filter(configurations, autoConfigurationMetadata);

this.fireAutoConfigurationImportEvents(configurations, exclusions);

return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);

}

}

@EnableAutoConfiguration注解就是从classpath中搜寻META-INF/spring.factories配置文件,并将其org.springframework.boot.autoconfigure.EnableAutoConfiguration对于的配置通过反射实例化对应的标注了@Configuration的JavaConfig配置类,并且加载到IOC容器中。

以web项目为例,在项目中加入了web环境依赖启动器,对应的org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration自动配置就会生效,打开自动配置就会发现,在配置类中通过全注解的方式对 Spring MVC 运行环境所需要环境进行了默认配置,包括前缀、后缀、试图解析器、MVC校验器等。

总结

Spring Boot底层实现自动配置的步骤:

spring boot 应用启动

@SpringBootApplication起作用

@EnableAutoConfiguration

@AutoConfigurationPackage

这个注解主要作用就是@Import({Registrar.class}),它通过Registrar类导入容器中,而Registrar的作用就是将扫描主配置类的包以及子包,并将对应的组件导入IOC容器中。

@Import({AutoConfigurationImportSelector.class})

它将 AutoConfigurationImportSelector 类导入容器中,AutoConfigurationImportSelector 类的作用是通过selectImports()方法执行的过程中,会使用内部工具类SpringFactoriesLoader,查找classpath上所有的jar包中的META-INF/spring.factories进行加载,实现将配置类信息交给Spring Factory加载器进行一系列的容器创建过程。

(3)@ComponentScan

@ComponentScan注解具体扫描包的路径,由Spring Boot主程序所在包的位置决定。在扫描的过程中由@AutoConfigurationPackage注解进行解析,从而得到Spring Boot主程序类所在包的具体位置

java校验框架源码解析_Spring Boot原理剖析和源码分析相关推荐

  1. Java集合类框架源码分析 之 LinkedList源码解析 【4】

    上一篇介绍了ArrayList的源码分析[点击看文章],既然ArrayList都已经做了介绍,那么作为他同胞兄弟的LinkedList,当然必须也配拥有姓名! Talk is cheap,show m ...

  2. 【java集合框架源码剖析系列】java源码剖析之ArrayList

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 本博客将从源码角度带领大家学习关于ArrayList的知识. 一ArrayList类的定义: public class Arr ...

  3. 顺序线性表 ---- ArrayList 源码解析及实现原理分析

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7738888.html ------------------------------------ ...

  4. Java校验框架-Oval

    Java校验框架-Oval 介绍 例子 代码 pom.xml Student.java ClassInfo.java TypeCheck.java StudentVerifyTest.java 运行测 ...

  5. java 并发框架源码_某网Java并发编程高阶技术-高性能并发框架源码解析与实战(云盘下载)...

    第1章 课程介绍(Java并发编程进阶课程) 什么是Disruptor?它一个高性能的异步处理框架,号称"单线程每秒可处理600W个订单"的神器,本课程目标:彻底精通一个如此优秀的 ...

  6. java 并发框架源码_Java并发编程高阶技术-高性能并发框架源码解析与实战

    Java并发编程高阶技术-高性能并发框架源码解析与实战 1 _0 Z' @+ l: s3 f6 r% t|____资料3 Z9 P- I2 x8 T6 ^ |____coding-275-master ...

  7. Java源码 JavaWeb开发框架 代码 SSH SSM OA ERP CRM Java项目[Java通用框架源码及开发视频教程]

    Java源码 JavaWeb开发框架 代码 SSH SSM OA ERP CRM Java项目 功能简介: A.代码生成器(开发利器) 生成Java各层次的类和JSP等文件,提高开发效率 B.阿里巴巴 ...

  8. 【Spring Boot实战】源码解析Spring Boot自动配置原理

    一.简介 Spring致力于让Java开发更简单,SpringBoot致力于让使用Spring进行Java开发更简单,SpringCloud致力于基于SpringBoot构建微服务生态圈,让微服务开发 ...

  9. 【java集合框架源码剖析系列】java源码剖析之java集合中的折半插入排序算法

    注:关于排序算法,博主写过[数据结构排序算法系列]数据结构八大排序算法,基本上把所有的排序算法都详细的讲解过,而之所以单独将java集合中的排序算法拿出来讲解,是因为在阿里巴巴内推面试的时候面试官问过 ...

最新文章

  1. [Win] 利用Memory DC抽取EXE的图标并保存为BMP文件
  2. .net学习笔记----WebConfig常用配置节点介绍
  3. 探秘蚂蚁金服分布式事务 Seata 的AT、Saga和TCC模式
  4. php mysql 高效,php+mysql 大容量数据高效分页效果(弃用limit)
  5. centos7.6 LNMP新版本
  6. Linux strace命令 一
  7. java速成课程_极*Java速成教程 - (5)
  8. 威纶触摸屏与S7-200SMART PLC通信的参数设置和连接电缆
  9. win10禁用全角_win10输入法全角半角怎么切换 快捷键使用教程
  10. Dynamic , Static or Seperate Schema Design (Convert No-SQL to ORDBMS)
  11. 关于PLC控制系统中电动机过载保护方法的探究
  12. iOS 开发值得拥有的75 个工具
  13. win10:取消电脑代理的方法
  14. 【组织架构】中国铁路上海局集团有限公司
  15. 终于有人把 单点 登录说清楚了!
  16. 小说作者推荐:没有颜色的无合集
  17. vsocde vue snippet 设置
  18. PHM2010刀具磨损数据集分享
  19. 在不停业务的情况下重启ES集群中的节点
  20. 如何宣传Android作为Bluetooth LE外围设备

热门文章

  1. 关掉windows自动更新
  2. 【图片和pdf】相关网站
  3. HTMLTestRunner 为什么用PyCharm(Eclipse)执行测试成功但无法生成报告
  4. ActiveMQ后台使用
  5. MySQL创建普通用户
  6. SpringBoot项目优化和Jvm调优(楼主亲测,真实有效)
  7. 【通知】+ java基础提升篇:Java 序列化的高级认识
  8. myeclipse添加使用hibernate框架详解
  9. 回溯算法 | 追忆那些年曾难倒我们的八皇后问题
  10. webpack从入门到精通(四)优化打包配置总结①