zoukankan      html  css  js  c++  java
  • SpringBoot的自动装配原理

    SpringBoot自动装配原理

    1. pom.xml
    • spring-boot-dependencies核心依赖在父工程中
    • 在引入springboot依赖时,不需要写版本,因为父工程中有版本仓库。
    1. 启动器 spring-boot-starter-xxx
    • 例如,spring-boot-starter-web,就会帮我们导入web环境所有的依赖。
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    1. 主程序SpringbootApplication .java
    package com.arlin.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
    }
    

    表面理解:

    • 注解@SpringBootApplication:标注这个类是一个springboot的应用
    • SpringApplication.run(SpringbootApplication.class, args);//将springboot应用启动

    深层次(源码分析):

    自动装配原理分析图

    img

    img

    • 注解@SpringBootApplication是一个复合 Annotation

    • 核心的两个注解:@SpringBootConfiguration和@EnableAutoConfiguration

    image-20210306202151496

    1. @SpringBootConfiguration:springboot的配置

    • @SpringBootConfiguration注解下还包含:@Configuration:表示一个普通的 JavaConfig 形式的 IoC 容器配置类
    • @Configuration注解下包含:@Component:表示该配置类也是容器中的一个组件

    2. @EnableAutoConfiguration :开启自动配置功能

    • 借助 @Import 的帮助,将所有符合自动配置条件的 bean 定义加载到 IoC 容器

    • AutoConfigurationImportSelector:导入哪些组件的选择器。将所有需要导入的组件以全类名的方式返回,这些组件会被添加其中

    image-20210306202418064

    ① 在AutoConfigurationImportSelector类中,实现了 DeferredImportSelector 接口,而 DeferredImportSelector 是继承 ImportSelector 类的。在 ImportSelector 中有个非常重要的方法:selectImports:批量将类注入到IOC容器

    // 1. 批量将类注入到IOC容器
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }
    

    ② selectImports方法调用getAutoConfigurationEntry方法

    // 2. selectImports方法调用getAutoConfigurationEntry方法
    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);
        }
    }
    

    image-20210306204709383

    ③ getAutoConfigurationEntry方法调用getCandidateConfigurations方法:获取候选配置

    // 3. 获取候选配置
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
        }
    

    ④ 调用SpringFactoriesLoader类中的loadFactoryNames方法,之后进入loadSpringFactories方法

    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());
    }
    
    

    可以看到在loadSpringFactories方法中调用如下路径:META-INF/spring.factories,从中获取EnableAutoConfiguration指定的值。

    image-20210306210013823

    META-INF/spring.factories配置文件中包含所有自动配置类:

    image-20210306213356600

    SpringBoot不需要写配置文件的原因是:SpringBoot所有配置都是在启动的时候进行扫描并加载,SpringBoot的所有自动配置类都在Spring.factories里面,但是不一定会生效,生效前要判断条件是否成立,只要导入了对应的start,就有对应的启动器,有了启动器就能帮我们进行自动配置类

    每一个xxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:

    • @ConditionalOnBean:当容器里有指定的bean的条件下。

    • @ConditionalOnMissingBean:当容器里不存在指定bean的条件下。

    • @ConditionalOnClass:当类路径下有指定类的条件下。

    • @ConditionalOnMissingClass:当类路径下不存在指定类的条件下。

    • @ConditionalOnProperty:指定的属性是否有指定的值
      比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。

    3. @ComponentScan

    @ComponentScan的功能其实就是自动扫描并加载符合条件的组件或 bean 定义,最终将这些 bean 定义加载到容器中。


    结论

    1. SpringBoot的自动装配原理

    Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,通过@Bean导入到Spring容器中,以Properties结尾命名的类是和配置文件进行绑定的。它能通过这些以Properties结尾命名的类中取得在全局配置文件中配置的属性,我们可以通过修改配置文件对应的属性来修改自动配置的默认值,来完成自定义配置。

    2. SpringbootApplication类的作用

    • 1.推断应用的类型是普通的项目还是Web项目
    • 2.查找并加载所有可用初始化器,设置到initializers属性中
    • 3.找出所有的应用程序监听器,设置到listeners属性中
    • 4.推断并设置main方法的定义类,找到运行的主类
  • 相关阅读:
    ABP 框架第一篇 ABP框架入门
    SpringBoot+mybatis plus 框架搭建
    诺依框架 第一章 springboot+vue前后端分离版本部署
    常用Web Service汇总网页
    Singleton单例模式
    告别无止境的增删改查Java代码生成器
    Builder生成器模式
    细说Java IO相关
    AbstractFactory抽象工厂模式
    设计模式关于模式的一些很基本的知识点
  • 原文地址:https://www.cnblogs.com/arlenlin/p/14492418.html
Copyright © 2011-2022 走看看