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

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

SpringBoot——SpringBoot运行原理分析

SpringBoot的核心思想:自动配置

一、分析pom.xml

4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.7.RELEASE
com.muhan
springboot_study01
0.0.1-SNAPSHOT
springboot_study01
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin

我们发现,在springboot的依赖中都是 spring-boot-starter-??? ,而这就是springboot的一个个场景启动器。如果我们想要配置web项目,那我们只需要导入springboot的web项目的启动器就可以了,springboot就会帮我们自动装配,就会帮我们配置我们需要的一切

父项目分析

我们从子项目中可以点击进入它的父项目

在这里插入图片描述
点进来之后我们可以看到,这个父项目就是springboot的主依赖,在父项目中配置了很多,字符编码,配置文件过滤,各种各样的插件等等,进入父项目,这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;

在这里插入图片描述

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

在这里插入图片描述

那我们以后想要自己导包配置依赖怎么办?

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

我们要想加一个包,就要去找这个包的启动器,一般我们都会去官网上去找。如果我们自己添加了一个包的版本和springboot不兼容,那么这个包就不会被spring托管,也就不会产生任何作用。

二、主程序类的启动器@SpringBootApplication

@SpringBootApplication(启动类上唯一的一个注解)

分析这个主程序类,我们发现这个类上有一个注解@SpringBootApplication,这个注解是用来标注这是一个springboot的主程序类,表明它是一个springboot应用,是创建项目时自己生成的,类中是程序主入口的main方法,方法里面有一个run方法用来运行springboot

在这里插入图片描述
我们点进去@SpringBootApplication这个注解,发现这个注解上有很多注解
在这里插入图片描述
在这里插入图片描述
下面我们一个个的去分析这些注解

1.四个元注解

其中前四个注解为元注解

@Target({
ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited
  • @Target({ElementType.TYPE}): 让被该注解修饰的注解可以作用于接口、类、枚举
  • @Retention(RetentionPolicy.RUNTIME): 注解会在class字节码文件中存在,在运行时可以通过反射获取到**
  • @Inherited @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。 如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
  • @Documented: 说明该注解将被包含在javadoc中

2.@SpringBootConfiguration注解(springboot配置注解,标注该类是一个配置类)

我们点进去这个注解,发现它除了三个元注解就只有一个@Configuration自定义注解

在这里插入图片描述
然后我们再点进去@Configuration注解,发现除了三个元注解还有一个@Component注解
在这里插入图片描述
得出结论:有了@Component这个注解,说明这个类就是一个spring的一个组件,或者说是springboot的一个组件,因为有了这个组件所以它才能存在于IOC容器中,才能被spring所管理,

3.@EnableAutoConfiguration(springboot自动装配注解,开启自动配置功能)

点进去@EnableAutoConfiguration这个注解,我们发现除了元注解外有两个自定义注解@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)

在这里插入图片描述

  • (1)@AutoConfigurationPackage——自动导入以及注册包

    点进去这个注解,发现它注册了一个注册器Registrar

    在这里插入图片描述
    我们再点进去这个Registrar,发现它实现了一个ImportBeanDefinitionRegistrar接口,实现这个接口让该类成为了拥有注册bean的能力
    在这里插入图片描述
    得出结论:@AutoConfigurationPackage注解就是一个自动导入以及注册包的注解,是因为它里面的Registrar实现了ImportBeanDefinitionRegistrar接口

  • (2)@Import(AutoConfigurationImportSelector.class)——@EnableAutoConfiguration自动导入的核心

    先点进去AutoConfigurationImportSelector中,发现这个类是一个很庞大的类,里面定义了许多自动配置,导包东西。
    在这里插入图片描述
    重点方法:getCandidteConfigurations()
    我们在这个类中找到getCandidteConfigurations()这个方法
    在这里插入图片描述

    protected List
    getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    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; }

    我们发现在getCandidteConfigurations()这个方法里又调用了SpringFactoriesLoader.loadFactoryNames()这个方法。

    这个方法是由SpringFactoriesLoader(spring的一个工厂加载器)去loadFactoryNames(获得它的名字)。里面传入了getSpringFactoriesLoaderFactoryClass(),参数,(获得这个类的Class),和getBeanClassLoader()参数(获得它里面的bean,就是所有组件的类加载器)

    List
    configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

    然后下面又使用了断言Assert,去断言这个configurations不为空,就去找一个文件META-INF/spring.factories,如果找不到就需要去这个文件里配置(大概是这个意思)

    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.");

    在这里插入图片描述

    getCandidteConfigurations()—>loadFactoryNames()

    分析完这些我们点进去loadFactoryNames这个方法看一下

    在这里插入图片描述
    getCandidteConfigurations()—>loadFactoryNames()—>loadSpringFactories()

    我们可以发现loadFactoryNames()中传入的getBeanClassLoader()类加载器 被传入loadSpringFactories()方法中了

    在这里插入图片描述
    来分析loadSpringFactories()方法,首先我们发现这个传入的参数ClassLoader前面有一个@Nullable的注解,这个注解的意思就是说该参数可以为空。然后我们分析代码发现如果ClassLoader不为空它就回去找这个资源FACTORIES_RESOURCE_LOCATION
    在这里插入图片描述
    META-INF/spring.factories
    我们点进去这个FACTORIES_RESOURCE_LOCATION看看到底要找哪个资源,点进去发现,原来如此!如果这个传过来的Classloader不为空,就回去找META-INF/spring.factories这个资源。真的是应证了之前的断言。
    在这里插入图片描述
    然后我们去找这个文件看看,在Maven里面的spring-boot-autoconfigure包下的META-INF/spring.factories
    在这里插入图片描述
    我们再看看这个文件里面有什么
    打开之后发现这个文件里面配置了许多许多东西,有初始化的配置,应用程序监听器配置,自动配置导入监听器,自动配置导入过滤器,自动配置,故障分析仪,模板可用性提供者配置…一大堆配置
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    META-INF/spring.factories—>WebMvcAutoConfiguration
    我们在Auto Configure自动配置中找到WebMvcAutoConfiguration这个配置类(其他类也一样),然后点进去
    在这里插入图片描述
    在这里插入图片描述

    WebMvcAutoConfiguration—>WebMvcAutoConfigurationAdapter

    WebMvcAutoConfiguration这个类是一个非常庞大的类,我们不去管它,直接去找这个类中WebMvcAutoConfigurationAdapter这个类,这个类就是WebMvc自动配置的适配器类

    在这里插入图片描述

    我们看见里面有两个注解:@Import(EnableWebMvcConfiguration.class)@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })这两个注解的作用是

    1.导入自动配置的文件,
    2.自动加载了一些配置文件:WebMvcProperties
    在这里插入图片描述
    WebMvcAutoConfigurationAdapter–>WebMvcProperties(类上注解的参数)
    然后我们点进去WebMvcProperties看一下都是什么,点进去发现它有一个前缀spring.mvc,而且它可以配置很多东西,比如格式化,国际化,日期格式等等…一些配置

在这里插入图片描述

然后我们再分析WebMvcProperties这个类,发现这个类是为了让我们去自己去配置一些东西的。那么我们分析一下,得出结论:每一个*****AutoConfiguration都对应一个****Properties配置

那么我们应该怎么去自己配置呢?

我们发现项目的resources目录下有一个application.properties文件(项目自动生成的),这个配置文件就是用来自定义配置的
在这里插入图片描述
根据刚才我们分析的源码,我们发现可以使用spring.mvc为前缀去配置一些东西(这里面的配置就是对应刚才我们找到的WebMvcProperties中的一些可以配置的东西)。假如我们再这里配置了,那么springboot的默认配置就会失效
在这里插入图片描述

当然我们还可以新建一个application.yml,并使用yml的风格去配置

在这里插入图片描述

分析WebMvcAutoConfigurationAdapter

然后我们分析WebMvcAutoConfigurationAdapter这个类,发现它配置了视图解析器
在这里插入图片描述
还配置了国际化资源,就是点击切换中英文功能
在这里插入图片描述
还有消息代码解析器,主要是用来处理乱码的
在这里插入图片描述
还配置了一些格式化的资源,比如时间日期就要用到这个对象,需要手动去配置
在这里插入图片描述
WebMvcAutoConfiguration—>WebMvcAutoConfigurationAdapter—>addResourceHandlers(重点方法)

然后!重点来了:还配置了资源处理器,addResourceHandlers方法可以让我们自己去添加自己想要的资源。我们分析代码发现,如果我们想要导入一个外部资源就要去遵循addResourceHandlers方法里面的规则。

在这里插入图片描述

@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled"); return; } Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl(); //如果/webjars/**下面已经有资源了就去classpath:/META-INF/resources/webjars/下去找 if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/") .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } //如过没有的话,就会去staticPathPattern下去找,staticPathPattern实质就是"/**",也就是/webjars/**下面说没有的话就去/**下去找 String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())) .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); }}

我们还发现一个问题,在springboot项目中并没有之前我们使用ssm框架时的webapp目录,那么我们的外部资源应该放在哪里呢?

在这里插入图片描述
然后我们再细细的分析这段代码,发现它会去找/webjars/**目录下面所有的资源,我们再之后的springboot的学习中会用到。

导入资源的第一种方式:使用webjars的导入一个jquery资源

在这里插入图片描述
找到jquery的webjars的maven依赖
在这里插入图片描述
将maven依赖复制到pom.xml中
在这里插入图片描述
然后我们可以去maven中查找jquery的包,我们可以找到该资源
在这里插入图片描述
然后我们再来分析这段代码,发现它还有自己给出的静态资源路径
在这里插入图片描述
我们继续点进去看一下到底它设定了哪些静态资源路径供我们使用,发现它返回了一个staticPathPattern
在这里插入图片描述
我们再点进去看一下,发现它给staticPathPattern赋值为"/**",也就是说静态资源放在根目录下也是可以的
在这里插入图片描述
分析完这个我们返回去继续分析WebMvcAutoConfigurationAdapter这个类

WebMvcAutoConfiguration—>WebMvcAutoConfigurationAdapter–>FaviconConfiguration(图标)

发现一个好玩的东西:可以设置网站的图标spring.mvc.favicon.enabled,可以用过这个组件去自定义网站的图标,但是图标名必须是**/favicon.ico,路径是根目录下的哪个位置,比如说resources目录下放一个名为favicon.ico的图标就可以将原有的小叶子替换掉
在这里插入图片描述
在这里插入图片描述

三、思维导图总结

在这里插入图片描述

三、主程序类的run方法的执行

在这里插入图片描述

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

你可能感兴趣的文章
Idea提示键和热部署配置以及git使用
查看>>
Deepin+Vscode搭建vue.js项目及Git操作
查看>>
基于Spring Security前后端分离式项目解决方案
查看>>
Vue3.0+Vite2.0项目框架搭建(一)
查看>>
Vue3.0+Vite2.0项目框架搭建(二)- 引入axios
查看>>
Vue3.0+Vite2.0项目框架搭建(三)- 引入Element3
查看>>
使用Vue CLI v4.5(+)搭建Vue3.0项目框架搭建
查看>>
Java集合框架
查看>>
线程协作与生产者消费者问题
查看>>
Vue入门
查看>>
非starter方式实现springboot与shiro集成
查看>>
Starter方式实现Springboot与Shiro集成
查看>>
移动端多页面应用(MPA)的开发(一)
查看>>
移动端多页面应用(MPA)的开发(二)
查看>>
移动端多页面应用(MPA)的开发(三)
查看>>
移动端多页面APP(MPA)开发体验
查看>>
基于深度学习知识追踪研究进展(综述)数据集模型方法
查看>>
linux常见命令与FileZilla
查看>>
PostgreSQL和ElasticSearch学习笔记
查看>>
java反射
查看>>