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


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

     

     

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

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframework.bootgroupId>
    4. <artifactId>spring-boot-starter-webartifactId>
    5. dependency>
    6. <dependency>
    7. <groupId>org.springframework.bootgroupId>
    8. <artifactId>spring-boot-testartifactId>
    9. <version>2.7.3version>
    10. <scope>testscope>
    11. dependency>
    12. dependencies>

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

    f64218b491e44607906e7ea066c59c85.png

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

     

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

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

    2  第一次父依赖

    1. <parent>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-parentartifactId>
    4. <version>2.7.3version>
    5. <relativePath/>
    6. parent>

    3 第二次父依赖

    1. <parent>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-dependenciesartifactId>
    4. <version>2.7.3version>
    5. parent>

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

    1. <groupId>org.springframework.bootgroupId>
    2. <artifactId>spring-boot-dependenciesartifactId>
    3. <version>2.7.3version>
    4. <packaging>pompackaging>
    5. <name>spring-boot-dependenciesname>

    5 进一步的深入了解一下

    1. <licenses>
    2. <license>
    3. <name>Apache License, Version 2.0name>
    4. <url>https://www.apache.org/licenses/LICENSE-2.0url>
    5. license>
    6. 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方法的介绍:请看流程图.

    814ccde58ef84e04a522ec5bb25ce335.png

     

    1. /**
    2. * @ SpringBootApplication 标注的是一个SpringBoot的应用
    3. */
    4. @SpringBootApplication //标记成SpringBoot启动类 启动类下面所有的包
    5. public class Application {
    6. public static void main(String[] args) {
    7. //将SpringBoot应用启动
    8. //SpringApplication 类
    9. //run方法
    10. SpringApplication.run(Application.class,args);
    11. }
    12. }
    1. package org.springframework.boot;
    2. public class SpringApplication {
    3. public static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt";
    4. public static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
    5. private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
    6. private static final Log logger = LogFactory.getLog(SpringApplication.class);
    7. static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();

    上面是有关:SpringApplication类的介绍

    1. package org.springframework.boot;
    2. public class SpringApplication {
    3. public static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt";
    4. public static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
    5. private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
    6. private static final Log logger = LogFactory.getLog(SpringApplication.class);
    7. static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();
    8. private Set> primarySources;
    9. private Set sources;
    10. private Class mainApplicationClass;
    11. private Mode bannerMode;
    12. private boolean logStartupInfo;

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

    1. public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) {
    2. return (new SpringApplication(primarySources)).run(args);
    3. }

    第二部分的总结

    SpringApplication类的作用

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

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

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

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

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

    Run方法

    • 1 判断项目类型

    • 2 推断当前主类

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

    • 4 找到运行主类


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

     

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

    第一模块的学习  

    47e87a489d6d4a79a9bc80b6a0d0f919.png

     

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

     第一层  Application

    1. package org.springframework.boot.autoconfigure;
    2. @Target({ElementType.TYPE})
    3. @Retention(RetentionPolicy.RUNTIME)
    4. @Documented
    5. @Inherited
    6. @SpringBootConfiguration
    7. @EnableAutoConfiguration
    8. @ComponentScan(
    9. excludeFilters = {@Filter(
    10. type = FilterType.CUSTOM,
    11. classes = {TypeExcludeFilter.class}
    12. ), @Filter(
    13. type = FilterType.CUSTOM,
    14. classes = {AutoConfigurationExcludeFilter.class}
    15. )}
    16. )

    第二层 public @interface SpringBootApplication {}

    注解:说明

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

    a341e241412447d791ee95d511fbf134.png

     第二模块:SpringBootConfiguration 让程序进入

    1. package org.springframework.boot;
    2. @Target({ElementType.TYPE})
    3. @Retention(RetentionPolicy.RUNTIME)
    4. @Documented
    5. @Configuration
    6. @Indexed
    7. public @interface SpringBootConfiguration {
    8. @AliasFor(
    9. annotation = Configuration.class
    10. )
    11. boolean proxyBeanMethods() default true;
    12. }

    然后进入@Configuration

    1. package org.springframework.context.annotation;
    2. @Target({ElementType.TYPE})
    3. @Retention(RetentionPolicy.RUNTIME)
    4. @Documented
    5. @Component
    6. public @interface Configuration {
    7. @AliasFor(
    8. annotation = Component.class
    9. )
    10. String value() default "";
    11. boolean proxyBeanMethods() default true;
    12. }

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

    1. //
    2. // Source code recreated from a .class file by IntelliJ IDEA
    3. // (powered by Fernflower decompiler)
    4. //
    5. package org.springframework.context.annotation;
    6. @Target({ElementType.TYPE})
    7. @Retention(RetentionPolicy.RUNTIME)
    8. @Documented
    9. @Component
    10. public @interface Configuration {
    11. @AliasFor(
    12. annotation = Component.class
    13. )
    14. String value() default "";
    15. boolean proxyBeanMethods() default true;
    16. }

    第三模块:

    074eeeeb94a24b90a2f46d587d59bf5e.png

     

     

    1. @Target({ElementType.TYPE})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. @Inherited
    5. @SpringBootConfiguration
    6. @EnableAutoConfiguration
    7. @ComponentScan(
    8. excludeFilters = {@Filter(
    9. type = FilterType.CUSTOM,
    10. classes = {TypeExcludeFilter.class}
    11. ), @Filter(
    12. type = FilterType.CUSTOM,
    13. classes = {AutoConfigurationExcludeFilter.class}
    14. )}

    进入@EnableAutoConfiguration程序中去

    1. @Target({ElementType.TYPE})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. @Inherited
    5. @AutoConfigurationPackage
    6. @Import({AutoConfigurationImportSelector.class})
    7. public @interface EnableAutoConfiguration {
    8. String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    9. Class[] exclude() default {};
    10. String[] excludeName() default {};
    11. }

    然后进入@AutoConfigurationPackage程序中去

    1. //
    2. // Source code recreated from a .class file by IntelliJ IDEA
    3. // (powered by Fernflower decompiler)
    4. //
    5. package org.springframework.boot.autoconfigure;
    6. import java.lang.annotation.Documented;
    7. import java.lang.annotation.ElementType;
    8. import java.lang.annotation.Inherited;
    9. import java.lang.annotation.Retention;
    10. import java.lang.annotation.RetentionPolicy;
    11. import java.lang.annotation.Target;
    12. import org.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar;
    13. import org.springframework.context.annotation.Import;
    14. @Target({ElementType.TYPE})
    15. @Retention(RetentionPolicy.RUNTIME)
    16. @Documented
    17. @Inherited
    18. @Import({Registrar.class})
    19. public @interface AutoConfigurationPackage {
    20. String[] basePackages() default {};
    21. Class[] basePackageClasses() default {};
    22. }

    然后返回到下面的页面

    1. package org.springframework.boot.autoconfigure;
    2. @Target({ElementType.TYPE})
    3. @Retention(RetentionPolicy.RUNTIME)
    4. @Documented
    5. @Inherited
    6. @AutoConfigurationPackage
    7. @Import({AutoConfigurationImportSelector.class})
    8. public @interface EnableAutoConfiguration {
    9. String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    10. Class[] exclude() default {};
    11. String[] excludeName() default {};
    12. }

    在上面的代码中找到:

    AutoConfigurationImportSelector.class 点进去

    第四模块:

    e78220dd4a5a412d9a487816070dcdae.png

     

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

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

    587a739bcf3e4219bbc39ad3ed49d5b2.png

     在上面的图片中找到

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

    获取所有的配置

    然后点击getCandidateConfigurations这个单词

    1. protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    2. if (!this.isEnabled(annotationMetadata)) {
    3. return EMPTY_ENTRY;
    4. } else {
    5. AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
    6. List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
    7. configurations = this.removeDuplicates(configurations);
    8. Set exclusions = this.getExclusions(annotationMetadata, attributes);
    9. this.checkExcludedClasses(configurations, exclusions);
    10. configurations.removeAll(exclusions);
    11. configurations = this.getConfigurationClassFilter().filter(configurations);
    12. this.fireAutoConfigurationImportEvents(configurations, exclusions);
    13. return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    14. }
    15. }

    然后你会发现

    f120a7d24e114df396b4bd7edb03f669.png

     

    1. protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    2. List configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
    3. ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
    4. 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.");
    5. return configurations;
    6. }

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

    SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass()

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

    1. protected Class getSpringFactoriesLoaderFactoryClass() {
    2. return EnableAutoConfiguration.class;
    3. }

    c283aefeed6b4efb8b748da8ffdfde21.png

     

    1227c50cc99645cf85baf366931543c9.png

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

    1. public static List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) {
    2. ClassLoader classLoaderToUse = classLoader;
    3. if (classLoader == null) {
    4. classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
    5. }
    6. String factoryTypeName = factoryType.getName();
    7. return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    8. }

    SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass()

    最后一个单词SpringFactoriesLoade  点击进去

    第六模块

    f583856d1a854baeb233e67a2aad6895.png

     

    1. public final class SpringFactoriesLoader {
    2. public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    3. private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
    4. static final Map>> cache = new ConcurrentReferenceHashMap();
    5. private SpringFactoriesLoader() {
    6. }
    1. protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    2. List configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
    3. ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
    4. 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.");
    5. return configurations;
    6. }
    1. private static Map> loadSpringFactories(ClassLoader classLoader) {
    2. Map> result = (Map)cache.get(classLoader);
    3. if (result != null) {
    4. return result;
    5. } else {
    6. HashMap result = new HashMap();
    7. try {
    8. Enumeration urls = classLoader.getResources("META-INF/spring.factories");
    9. while(urls.hasMoreElements()) {
    10. URL url = (URL)urls.nextElement();
    11. UrlResource resource = new UrlResource(url);
    12. Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    13. Iterator var6 = properties.entrySet().iterator();
    14. while(var6.hasNext()) {
    15. Entry entry = (Entry)var6.next();
    16. String factoryTypeName = ((String)entry.getKey()).trim();
    17. String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
    18. String[] var10 = factoryImplementationNames;
    19. int var11 = factoryImplementationNames.length;
    20. for(int var12 = 0; var12 < var11; ++var12) {
    21. String factoryImplementationName = var10[var12];
    22. ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
    23. return new ArrayList();
    24. })).add(factoryImplementationName.trim());
    25. }
    26. }
    27. }

     

    f9fd28be20a24a37a432a9e8df23aecc.png

     

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

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

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

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

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

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

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

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

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

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

    • 实现了SpringBoot自动配置

     

     

  • 相关阅读:
    【1431】java学习网站系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
    HTML5开发实例-3D全景(ThreeJs全景Demo) 详解(图)
    数据库系统概论——数据库恢复技术
    springboot校园安全通事件报告小程序-计算机毕业设计源码02445
    Java“牵手”微店商品列表数据,关键词搜索微店商品数据接口,微店API申请指南
    微突发丢包的艺术
    【第4天】SQL快速入门-多表查询(SQL 小虚竹)
    Linux下yum源配置实战 1
    01程序执行原理
    java-python-net-php-基于SSM的汽车保险销售信息管理系统计算机毕业设计程序
  • 原文地址:https://blog.csdn.net/qq_56248592/article/details/126707235