2022年9月5号 SpringBoot自动配置原理初步了解SpringBoot原理。

第一点解析Pom.xml文件信息下面是配置文件的具体信息。


<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId><version>2.7.3</version><scope>test</scope></dependency>
</dependencies>

第一张图:带你了解Pom.xml文件:

图一的流程来解析pom.xml文件的信息

让我们来看一下上面流程图的过程吧!这里涉及到源码

1 认真观察你会发现pom.xml文件中有两次的父依赖的关系

2  第一次父依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.3</version><relativePath/> <!-- lookup parent from repository --></parent>

3 第二次父依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.7.3</version></parent>

4 spring-boot-dependencies 这个包在Maven的学习中见过吧

<groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.7.3</version><packaging>pom</packaging><name>spring-boot-dependencies</name>

5 进一步的深入了解一下

 <licenses><license><name>Apache License, Version 2.0</name><url>https://www.apache.org/licenses/LICENSE-2.0</url></license></licenses>

6 第一次小的总结:spring-boot-dependencies 帮我们管理了SpringBoot开发环境中应用中所有应用中所有的依赖版本,解决了第三方库的冲突问题。

因此:spring-boot-dependencies称为 SpringBoot版本仲裁中心。

7 启动器的概念:   spring-boot-starter-xxx  简称为启动器 

启动器:说白了又是SpringBoot的启动场景

比如 spring-boot-starter-web,他又会导入所有的web环境所有的依赖

8 springboot官网介绍的应用场景的地址 在下面 

https://docs.spring.io/spring-boot/docs/current/reference/html/dependency-versions.html#appendix.dependency-versions

9 下面是一些Springboot应用场景在官网中找到的

spring-boot-starter-test 起动器测试弹簧启动应用程序和库包括JUnit木星,Hamcrest和5
spring-boot-starter-thymeleaf 起动器构建MVC web应用程序使用Thymeleaf视图
spring-boot-starter-validation 起动器与Hibernate验证框架的使用Java Bean验证
spring-boot-starter-web 为构建web起动器,包括RESTful,使用Spring MVC应用程序。 使用Tomcat作为默认嵌入式容器
spring-boot-starter-web-services 起动器使用Spring Web服务
spring-boot-starter-webflux 起动器构建WebFlux应用程序使用Spring框架的反应网络的支持
spring-boot-starter-websocket 起动器来构建使用Spring框架的WebSocket支持WebSocket应用程序

第二张图:关于SpringApplication和Run方法的介绍:请看流程图.


/*** @ SpringBootApplication 标注的是一个SpringBoot的应用*/
@SpringBootApplication //标记成SpringBoot启动类 启动类下面所有的包public class Application {public static void main(String[] args) {//将SpringBoot应用启动//SpringApplication 类//run方法SpringApplication.run(Application.class,args);}
}

package org.springframework.boot;public class SpringApplication {public static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt";public static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";private static final Log logger = LogFactory.getLog(SpringApplication.class);static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();

上面是有关:SpringApplication类的介绍

package org.springframework.boot;public class SpringApplication {public static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt";public static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";private static final Log logger = LogFactory.getLog(SpringApplication.class);static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();private Set<Class<?>> primarySources;private Set<String> sources;private Class<?> mainApplicationClass;private Mode bannerMode;private boolean logStartupInfo;

上面是关于源码Run方法的介绍:关键在下面 new SpringApplication

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return (new SpringApplication(primarySources)).run(args);}

第二部分的总结

SpringApplication类的作用

这个类主要做了以下四件事情

  • 1.推断应用的类型是普通的项目还是Web项目

  • 2.查找并加载所有可用初始化器,设 置到initializers属性中.

  • 3 找出所有的应用程序监听器,设置到listeners属性中

  • 4.推断并设置main方法的定义类,找到运行的主类

Run方法

  • 1 判断项目类型

  • 2 推断当前主类

  • 3 设置监听器 获取上下文 全面接管SpringMvc配置

  • 4 找到运行主类


第三部分 @SpringBootApplication 一个注解才是SpringBoot的自动配置原理的核心。

SpringBoot自动配置原理核心@SpringBoot程序:

第一模块的学习

package com.java.controller.com.java;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;// @SpringBootApplication  SpringBoot启动类(入口)
//@Configuration Spring.xml 页是配置类
//ComponentScan  =<context:ComponentScan ></context-ComponentScan > 扫描包名
//Spring底层在解析配置类:回去解析@ComponentScan,读取basePackage
//如果没有读取到,会将当前配置类所在的包当成扫描包  package com.java.controller.com.java;
//位置:最好放在需要扫描的包的根目录下面,或者说放在所有Bean的项目中/*** @ SpringBootApplication 标注的是一个SpringBoot的应用*/
@SpringBootApplication //标记成SpringBoot启动类 启动类下面所有的包public class Application {public static void main(String[] args) {//将SpringBoot应用启动//SpringApplication 类//run方法SpringApplication.run(Application.class,args);}
}

第一层  Application

package org.springframework.boot.autoconfigure;@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 {}

注解:说明

  • @SpringBootConfiguration springboot的配置
  • @Configuration   spring配置类
  • @Component   说明这也是一个Spring组件
  • @EnableAutoConfiguration  自动配置
  • @AutoConfigurationPackage 自动配置包 导入了选择器
  • @Import({AutoConfigurationImportSelector.class}) 自动配置 包的注册

第二模块:SpringBootConfiguration 让程序进入


package org.springframework.boot;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}

然后进入@Configuration

package org.springframework.context.annotation;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {@AliasFor(annotation = Component.class)String value() default "";boolean proxyBeanMethods() default true;
}

最后进入到@Component中去你会发现下面内容

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package org.springframework.context.annotation;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {@AliasFor(annotation = Component.class)String value() default "";boolean proxyBeanMethods() default true;
}

第三模块:

@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}
)}

进入@EnableAutoConfiguration程序中去

@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 {};
}

然后进入@AutoConfigurationPackage程序中去

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package org.springframework.boot.autoconfigure;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar;
import org.springframework.context.annotation.Import;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {String[] basePackages() default {};Class<?>[] basePackageClasses() default {};
}

然后返回到下面的页面

package org.springframework.boot.autoconfigure;@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 {};
}

在上面的代码中找到:

AutoConfigurationImportSelector.class 点进去

第四模块:

package org.springframework.boot.autoconfigure;public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {private static final AutoConfigurationImportSelector.AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationImportSelector.AutoConfigurationEntry();private static final String[] NO_IMPORTS = new String[0];private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";private ConfigurableListableBeanFactory beanFactory;private Environment environment;private ClassLoader beanClassLoader;private ResourceLoader resourceLoader;private AutoConfigurationImportSelector.ConfigurationClassFilter configurationClassFilter;public AutoConfigurationImportSelector() {}

在上面的源码的基础上往下翻

在上面的图片中找到

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

获取所有的配置

然后点击getCandidateConfigurations这个单词

 protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {AnnotationAttributes attributes = this.getAttributes(annotationMetadata);List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);configurations = this.removeDuplicates(configurations);Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = this.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}}

然后你会发现

 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");return configurations;}

第五模块:下面的单词有三个重点

SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass()

先看第一个getSpringFactoriesLoaderFactoryClass()  单点击是    return EnableAutoConfiguration.class 程序的出口找到

protected Class<?> getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class;}

在点击第二个单词:loadFactoryNames 获取所有的配置名 点进去看一下

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse = classLoader;if (classLoader == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName = factoryType.getName();return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());}

SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass()

最后一个单词SpringFactoriesLoade  点击进去

第六模块

public final class SpringFactoriesLoader {public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);static final Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap();private SpringFactoriesLoader() {}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");return configurations;}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {Map<String, List<String>> result = (Map)cache.get(classLoader);if (result != null) {return result;} else {HashMap result = new HashMap();try {Enumeration urls = classLoader.getResources("META-INF/spring.factories");while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);Iterator var6 = properties.entrySet().iterator();while(var6.hasNext()) {Entry<?, ?> entry = (Entry)var6.next();String factoryTypeName = ((String)entry.getKey()).trim();String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());String[] var10 = factoryImplementationNames;int var11 = factoryImplementationNames.length;for(int var12 = 0; var12 < var11; ++var12) {String factoryImplementationName = var10[var12];((List)result.computeIfAbsent(factoryTypeName, (key) -> {return new ArrayList();})).add(factoryImplementationName.trim());}}}

结论: springboot所有 自动配置都是在启动的时候扫描并加载: spring . factories所有的自动配置类都在这里面,但是不一-定生效, 要判断条件是否成立,只要导入了对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功!

  • springboot在启动的时候,从类路径下/META-INF/ spring . factories获取指定的值;

  • 将这些自动配置的类导入容器,自动配置就会生效,帮我进行自动配置!

  • 以前我们需要自动配置的东西,现在springboot帮我们做了

  • 整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.2.0.RELEASE.jar这个包下

  • 它会把所有需要导入的组件,以类名的方式返回,这些

  • 组件就会被添加到容器;

  • 容器中也会存在非常多的xxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件;并自动配置,@Configuration ,JavaConfig!

  • 有了自动配置类,免去了我们手动编写配置文件的工作!

  • 核心要义 继承继承在继承 封装封装在封装

  • 实现了SpringBoot自动配置

SpringBoot《第二课》相关推荐

  1. 继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错? springboot 两种方式稳定解决跨域问题

    继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错???springboot 两种方式稳定解决跨域问题! 之前我写了一篇文章,来解决CORS报错 ...

  2. Dockerfile springboot项目拿走即用,将yml配置文件从外部挂入容器

    Dockerfile 将springboot项目jar包打成镜像,并将yml配置文件外挂. # 以一个镜像为基础,在其上进行定制.就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜 ...

  3. SpringBoot部署脚本,拿走即用!

    一个可以直接拿来使用的shell脚本,适用于springboot项目 #!/bin/bash # 这里可替换为你自己的执行程序,其他代码无需更改,绝对路径相对路径均可. # 若使用jenkins等工具 ...

  4. SpringBoot项目使用nacos,kotlin使用nacos,java项目使用nacos,gradle项目使用nacos,maven项目使用nacos

    SpringBoot项目使用nacos kotlin demo见Gitte 一.引入依赖 提示:这里推荐使用2.2.3版本,springboot与nacos的依赖需要版本相同,否则会报错. maven ...

  5. springboot整合swagger2之最佳实践

    来源:https://blog.lqdev.cn/2018/07/21/springboot/chapter-ten/ Swagger是一款RESTful接口的文档在线自动生成.功能测试功能框架. 一 ...

  6. SpringBoot中实现quartz定时任务

    Quartz整合到SpringBoot(持久化到数据库) 背景 最近完成了一个小的后台管理系统的权限部分,想着要扩充点东西,并且刚好就完成了一个自动疫情填报系统,但是使用的定时任务是静态的,非常不利于 ...

  7. Springboot 利用AOP编程实现切面日志

    前言 踏入Springboot这个坑,你就别想再跳出来.这个自动配置确实是非常地舒服,帮助我们减少了很多的工作.使得编写业务代码的时间占比相对更大.那么这里就讲一下面向切面的日志收集.笔者使用lomb ...

  8. 【Springboot】日志

    springBoot日志 1.目前市面上的日志框架: 日志门面 (日志的抽象层):                JCL(Jakarta Commons Logging)                ...

  9. 【springboot】配置

    配置文件 SpringBoot使用一个全局的配置文件,配置文件名是固定的: •application.properties •application.yml 配置文件的作用:修改SpringBoot自 ...

  10. 【springboot】入门

    简介: springBoot是spring团队为了整合spring全家桶中的系列框架做研究出来的一个轻量级框架.随着spring4.0推出而推出,springBoot可以説是J2SEE的一站式解决方案 ...

最新文章

  1. mysql binlog的查询
  2. CUDA:利用Pytorch查看自己电脑上CUDA版本及其相关信息
  3. vue init失败解决方案-终极版
  4. 如何使用代码确定设备屏幕大小类别(小,普通,大,xlarge)?
  5. 【路径规划】基于matlab蚁群和粒子群算法双机器人协调路径规划【含Matlab源码 045期】
  6. 种一棵树最好的时间是十年前,其次是现在。
  7. git输入 ssh-keygen -t rsa 后只显示Generating public/private rsa key pair. 然后就直接跳出了
  8. 服务器安装linux系统教程
  9. 千呼万唤始出来—2019 FLAG
  10. Python如何使用Any和All?代码示例和解析
  11. python从云端服务器读数据_云服务器简单实现Python自动运维
  12. 菜鸟Django--更改和删除
  13. 羡慕华为人年薪110万?先看看华为员工的16项标准!
  14. Android studio 编译错误:CreateProcess error=206, 文件名或扩展名太长。
  15. FPGA数字信号处理(四)Quartus FIR IP核实现
  16. Carrot保卫萝卜
  17. 2023年广东数据分析师CPDA认证招生简章(理论+实战)
  18. easyui datebox时间控件改为年月视图,值也为年月
  19. SQL Server的彻底卸载与再次安装
  20. 八类患病番茄叶片图像数据集

热门文章

  1. HBase2.x(七)Master 架构
  2. sina.cn邮箱邀请
  3. OSChina 周六乱弹 —— 感谢女装红薯开办了这个网站
  4. 今天安利几个实用的APP给你
  5. r910服务器增加内存,dellr910服务器硬件手册及安装方法
  6. 计算机怎么知道乘法优先,计算器算个明白.doc
  7. code flattening —— conversion to R1CS——formulation of QAP
  8. 程序员是这样炼成的(2)-选择成熟的柿子还是生柿子
  9. Pinyin4j之Pinyin4jUtils工具类
  10. 生成真正的随机数(非伪随机数)