博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot运行原理探究
阅读量:3967 次
发布时间:2019-05-24

本文共 7277 字,大约阅读时间需要 24 分钟。

1.Pom.xml

父依赖

其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!

org.springframework.boot
spring-boot-starter-parent
2.3.4.RELEASE

点进去,发现还有一个父依赖

org.springframework.boot
spring-boot-dependencies
2.3.4.RELEASE

这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;

以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本 了

2.启动器 spring-boot-starter

org.springframework.boot
spring-boot-starter-web

springboot-boot-starter-xxx:就是spring-boot的场景启动器

spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;

SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些 starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我 们未来也可以自己自定义 starter

3.主启动类

默认的主启动类

package com.loey;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;//SpringBoot项目启动入口类@SpringBootApplication//springboot核心注解,主要用于开启spring自动配置public class Application {
//springboot项目代码必须放到Application类所在的同级目录或下级目录 public static void main(String[] args) {
//以为是启动了一个方法,没想到启动了一个服务 SpringApplication.run(Application.class, args); }}

@SpringBootApplication

作用: 标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方 法来启动SpringBoot应用;

进入这个注解:可以看到上面还有很多其他注解

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {
//.....}

@ComponentScan

这个注解在Spring中很重要 ,它对应XML配置中的元素。

作用: 自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中

@SpringBootConfiguration

作用: SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;

我们继续进去这个注解查看

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration {
//....}

点进去:

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Configuration {
//....}

这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;

里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用! 我们回到 SpringBootApplication 注解中继续看

@EnableAutoConfiguration

@EnableAutoConfiguration : 开启自动配置功能

以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ; @EnableAutoConfiguration 告诉SpringBoot开启自动配置功能,这样自动配置才能生效;

点进注解接续查看:

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {
//...}

@AutoConfigurationPackage : 自动配置包

点进去查看

@Import(AutoConfigurationPackages.Registrar.class)public @interface AutoConfigurationPackage {
//....}

@import :Spring底层注解@import , 给容器中导入一个组件

Registrar.class 作用: 将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;

这个分析完了,退到上一步,继续看

@Import({AutoConfigurationImportSelector.class}) :给容器导入组件 ;
AutoConfigurationImportSelector : 自动配置导入选择器,那么它会导入哪些组件的选择器呢? 我们 点击去这个类看源码:

1、这个类中有一个这样的方法

// 获得候选的配置protected List
getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//这里的getSpringFactoriesLoaderFactoryClass()方法 //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration List
configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }

2、这个方法又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类 loadFactoryNames() 方法

public static List
loadFactoryNames(Class
factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName(); //这里它又调用了 loadSpringFactories 方 return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }

3、我们继续点击查看 loadSpringFactories 方法

private static Map
> loadSpringFactories(@Nullable ClassLoader classLoader) {
//获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注 的类本身 MultiValueMap
result = cache.get(classLoader); if (result != null) {
return result; } try {
//去获取一个资源 "META-INF/spring.factories" Enumeration
urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); //将读取到的资源遍历,封装成为一个Properties while (urls.hasMoreElements()) {
URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry
entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }

4、发现一个多次出现的文件: spring.factories ,全局搜索它

spring.factories

我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!

在这里插入图片描述

在这里插入图片描述

WebMvcAutoConfiguration

我们在上面的自动配置类随便找一个打开看看,比如 : WebMvcAutoConfiguration
在这里插入图片描述
可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看 着熟悉一下!
所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中 对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容 器中

结论:

  • 1.SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取 EnableAutoConfiguration指定的值
  • 2 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
  • 3 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
  • 4.它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需 要的所有组件 , 并配置好这些组件 ;
  • 5.有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作

在这里插入图片描述

SpringApplication

不简单的方法,开启了一个服务

//SpringBoot项目启动入口类@SpringBootApplication//springboot核心注解,主要用于开启spring自动配置public class Application {
//springboot项目代码必须放到Application类所在的同级目录或下级目录 public static void main(String[] args) {
SpringApplication.run(Application.class, args); }}

SpringApplication.run分析 ,分析该方法主要分两部分,

  • 一部分是SpringApplication的实例化,
  • 二是run方法的执行;

SpringApplication

这个类主要做了以下四件事情:
1、推断应用的类型是普通的项目还是Web项目
2、查找并加载所有可用初始化器 , 设置到initializers属性中
3、找出所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类

查看构造器

public SpringApplication(ResourceLoader resourceLoader, Class
... primarySources) {
this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }

run方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

转载地址:http://sluki.baihongyu.com/

你可能感兴趣的文章
zedboard烧写程序到FLASH,用于QSPI Flash启动
查看>>
软件工程师,你必须知道的20个常识
查看>>
常用STL算法2_查找
查看>>
常用STL算法3_排序
查看>>
常用STL算法4_拷贝和替换
查看>>
常用STL算法5_算术和生成
查看>>
常用STL算法6_集合
查看>>
STL综合案例
查看>>
数据结构 的可视化
查看>>
比较版本号的大小 新旧
查看>>
01背包问题
查看>>
O(logn)时间复杂度求Fibonacci数列
查看>>
【转】腾讯十年运维老兵:运维团队的五个“杀手锏”
查看>>
Iterator_traits
查看>>
Zedboard中的SPI通信记录文档(已实现)
查看>>
zigbee学习笔记2----cc2530 IO实验
查看>>
zigbee学习笔记4----初次接触zstack
查看>>
Android 发布到google Play的app搜索不到问题的解决
查看>>
Flutter 网络请求之基于dio的简单封装
查看>>
Flutter UI基础 - 路由之Navigator详解
查看>>