@


前言

前面第一章的内容基本上都是基于注解的Spring内容,想要学好SpringBoot这些Spring基础必不可少。从这章开始就是SpringBoot了,首先学习一下SpringBoot最重要的自动装配原理。

一句话概括SpringBoot的自动配置原理就是:启动时加载所有,最终按照条件进行装配。

本小节重点注解结构列图如下:

@SpringBootApplication:主程序注解;

  • @SpringBootConfiguration:表名核心配置类;

    • @Configuration:表名配置类;
  • @ComponentScan:开启包扫描;
  • @EnableAutoConfiguration:启用自动配置;
    • @AutoConfigurationPackage:自动配置包,指定了自动配置包的默认规则;

      • @Import(AutoConfigurationPackages.Registrar.class):容器中导入Registrar组件;
    • @Import(AutoConfigurationImportSelector.class):【重要】按照条件配装规则@Conditional,按需配置;

注:在说明注解时,第一点加粗为注解中文含义,第二点为一般加在哪身上,缩进或代码块为示例,如:

@注解

  • 中文含义
  • 加在哪
  • 其他……
    • 语句示例
    //代码示例

1. 引入配置文件与配置绑定

在理解自动装配原理之前,还需要知道配置绑定相关注解。

引入配置文件常用@ImportResource注解:

@ImportResource

  • 配置引入;
  • 用于类上;
  • 用于引入配置文件,常用于老项目(需要保留大量xml文件的项目);
    • @ImportResource("classpath:beans.xml") 引入beans.xml配置文件。

配置绑定的核心注解为@ConfigurationProperties,指读取properties文件中的内容,封装进JavaBean中,以供随时使用。

@ConfigurationProperties

  • 属性配置
  • 用于POJO类上;

配置绑定有两种形式:

1.1 @ConfigurationProperties + @EnableConfigurationProperties

  • EnableConfigurationProperties:启用配置属性;

  • POJO类上写@ConfigurationProperties,在配置类上写@EnableConfigurationProperties

  • @EnableConfigurationProperties的两个核心功能:将按照制定规则与配置文件绑定、将组件导入容器中;

    • 例:将Car组件自动注册进容器中:
    //配置类
    @EnableConfigurationProperties(Car.class)
    public class MyConfig {
    } //POJO类
    @ConfigurationProperties(prefix = "mycar")
    public class Car {
    private String brand;
    private Integer price;
    }
    #配置文件
    mycar:
    brand: 小鹏
    price: 100000

1.2 @ConfigurationProperties + @Component

  • Component:组件注入;

  • POJO类上同时标注这两个注解;

  • @Component表示将POJO类作为组件注册进容器中,只有在容器中的组件, 才会拥有SpringBoot提供的强大功能;

    • 例:将Car组件自动注册进容器中:
    @Component
    @ConfigurationProperties(prefix = "mycar") //prefix表示前缀
    public class Car {
    private String brand;
    private Integer price;
    }
    #配置文件
    mycar:
    brand: 小鹏
    price: 100000

2. 自动配置原理【总述】

SpringBoot自动配置的核心注解是@SpringBootApplication,这是个十分【重要】的注解。

@SpringBootApplication

  • SpringBoot应用
  • 用在主启动类上;
  • 表名该应用是个SpringBoot应用,并且指定主启动类入口;
  • 是SpringBoot的核心注解,也是个合成注解,由3个注解组合而成@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan);
    • SpringBoot源码:
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication{
    ……
    }

主程序注解结构列图【精髓】

建议在下面学习底层注解时对照结构图。

@SpringBootApplication:主程序注解;

  • @SpringBootConfiguration:表名核心配置类;

    • @Configuration:表名配置类;
  • @ComponentScan:开启包扫描;
  • @EnableAutoConfiguration:启用自动配置;
    • @AutoConfigurationPackage:自动配置包,指定了自动配置包的默认规则;

      • @Import(AutoConfigurationPackages.Registrar.class):容器中导入Registrar组件;
    • @Import(AutoConfigurationImportSelector.class):【重要】按照条件配装规则@Conditional,按需配置;

下面将对@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan三个注解逐一分析。

3. 引导加载自动配置类【三注解源码分析】

这三个注解中,@EnableAutoConfiguration为核心。

@SpringBootConfiguration

  • 配置注解
  • 标注类上;
  • 底层是一个@Configuration,代表当前类是一个配置类。在这里指核心配置类。

@ComponentScan

  • 开启包扫描

  • 标注类上;

  • 可以指定扫描路径,扫描到的包里的注解才能生效。在这里自定义了两个扫描器。

    • 例:@ComponentScan(basePackages = {"com.dlhjw"})

@EnableAutoConfiguration

  • 启用自动配置
  • 标注在配置类上;
  • 需要在配置类里写,表示开启属性配置功能,将指定的组件自动注册到容器中;
  • 重要注解,实现注解@SpringBootApplication的核心功能,其本身也是一个合成注解。
    • 注解源码,由@AutoConfigurationPackage@Import合成:
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    ……
    }

第一个注解:

@AutoConfigurationPackage
  • 自动配置包
  • 用在类上;
  • 指定了自动配置包的默认规则:将主程序类MainApplication所在包下的所有组件用Registrar方法批量注册进容器里。
    • 注解源码:
    @Import(AutoConfigurationPackages.Registrar.class)  //给容器中导入一个组件
    public @interface AutoConfigurationPackage {
    ……
    }

源码级分析:

解释SpringBoot默认的扫描路径为主程序类MainApplication所在包及以下:

Registrar方法源码如下:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
} //Registrar方法传递两个参数,第一个是注解的源信息AnnotationMetadata,这个注解标在主程序类MainApplication上(合成注解层层传递)
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//Registrar方法利用注解源信息获取到主程序MainApplication所在包名com.dlhjw.boot,封装成数组,注册进容器里。
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
} public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
  • 即:@AutoConfigurationPackage注解的含义是:将指定的一个包下的所有组件导入进容器。

第二个注解

@Import(AutoConfigurationImportSelector.class)【重要】
  • 引入自动配置类;
  • 用在类上;
  • 在SpringBoot初始启动时导入127个自动配置类,按照条件配装规则@Conditional,按需配置;

源码级分析:

总体上:利用Selector机制给容器批量导入自动配置类;(底层 -> 实现)

  1. 首先从META-INF/spring.factories位置加载一个文件。即默认扫描当前系统里面所有META-INF/spring.factories位置的文件。其中最重要的是spring-boot-autoconfigure-2.3.4.RELEASE.jar包里的META-INF/spring.factories(SpringBoot兼容全场景的127个自动配置类就在这里,即xxxxAutoConfiguration);
  2. 接着使用Spring的工厂加载类loadSpringFactories得到所有的组件;
  3. 然后调用getCandidateConfigurations()获取到所有需要导入到容器中的配置类(默认导入导容器中的127个全类名组件)
  4. 接着利用getAutoConfigurationEntry(annotationMetadata)方法获取自动配置集合
  5. 【核心】最后对getAutoConfigurationEntry(annotationMetadata)获取到的配置进行封装,封装成selectImports(AnnotationMetadata am)方法,返回String数组,数组里说明了需要导入的自动配置类(组件)。

4. 按需开启自动配置项【核心】

虽然127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration

但我们不一定全部都会用到,需要按照条件装配规则@Conditional,按需配置。

例:给容器中加入文件上传解析器;

@Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
//给@Bean标注的方法传入了对象参数,这个参数的值会从容器中找。
//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
return resolver;
}

5. 修改默认配置【定制化配置】

约定大于配置思想: SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先

@ConditionalOnMissingBean

  • 条件装配
  • 用在方法上;
  • SpringBoot源码里经常会有@ConditionalOnMissingBean注解,表示当容器中没有该组件时,才会注册SpringBoot默认的。
    //源码里
    @Bean
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
    }

用户配置方式(定制化配置):

定制化配置基于属性绑定注解@EnableConfigurationProperties与修改默认配置方法

  1. 在config包下的配置文件类上标注引入配置文件注解@ImportResource

    @ImportResource("classpath:beans.xml")
    public class MyConfig(){
    //(*)
    }
  2. 在config包下的配置文件类里(*)处配置用户方式

    @Bean
    public CharacterEncodingFilter myFilter() {
    ……
    }
  3. application.properties 配置文件里配置(推荐)

*6. 改变扫描路径

SpringBoot默认扫描主程序所在包及其下面的所有子包里面的组件,但可以改变扫描路径。

改变扫描路径:

@SpringBootApplication(scanBasePackages="com.dlhjw")

  • 扫描com.dlhjw包下的注解;

@ComponentScan("com.dlhjw")

  • 扫描com.dlhjw包下的注解;

排除自动扫描:

@SpringBootApplication(exclude={XX.class,YY.class})

  • 例:@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)取消数据库配置。

7. 自动配置总结

一句话概括SpringBoot的自动配置原理就是:启动时加载所有,最终按照条件进行装配。

即:

  • SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。从xxxxProperties里面取,xxxProperties和配置文件进行了绑定;
  • 生效的配置类就会给容器中装配很多组件,只要容器中有这些组件,相当于这些功能就有了;
  • 由此可得:定制化配置基于属性绑定注解@EnableConfigurationProperties修改默认配置方法
    • 用户直接自己@Bean替换底层的组件(基于SpringBoot的@ConditionalOnMissingBean);
    • 用户去看这个组件是获取的配置文件什么值就去修改(基于SpringBoot的属性绑定注解@EnableConfigurationProperties);
  • 即:xxxxxAutoConfiguration ---> 组件 ---> xxxxProperties里面拿值 ---> application.properties

主程序注解结构列图

这里再列一下结构图,因为本小节的精髓都在这了。

@SpringBootApplication:主程序注解;

  • @SpringBootConfiguration:表名核心配置类;

    • @Configuration:表名配置类;
  • @ComponentScan:开启包扫描;
  • @EnableAutoConfiguration:启用自动配置;
    • @AutoConfigurationPackage:自动配置包,指定了自动配置包的默认规则;

      • @Import(AutoConfigurationPackages.Registrar.class):容器中导入Registrar组件;
    • @Import(AutoConfigurationImportSelector.class):【重要】按照条件配装规则@Conditional,按需配置;

其他说明:

  • 若在配置类里只有一个有参构造器,说明有参构造器里的所有属性都会从属性里确定;(4.2.x 设置静态页面)

最后

新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!

SpringBoot | 2.1 SpringBoot自动装配原理的更多相关文章

  1. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  2. springboot自动装配原理,写一个自己的start

    springboot自动装配原理 第一次使用springboot的时候,都感觉很神奇.只要加入一个maven的依赖,写几行配置,就能注入redisTemple,rabbitmqTemple等对象. 这 ...

  3. SpringBoot嵌入式Tomcat的自动配置原理

    在读本篇文章之前如果你读过这篇文章SpringBoot自动装配原理解析应该会更加轻松 准备工作 我们知道SpringBoot的自动装配的秘密在org.springframework.boot.auto ...

  4. SpringBoot:配置文件及自动配置原理

    西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处!防君子不防小人,共勉! SpringBoot ...

  5. SpringBoot启动代码和自动装配源码分析

    ​ 随着互联网的快速发展,各种组件层出不穷,需要框架集成的组件越来越多.每一种组件与Spring容器整合需要实现相关代码.SpringMVC框架配置由于太过于繁琐和依赖XML文件:为了方便快速集成第三 ...

  6. Eureka 系列(03)Spring Cloud 自动装配原理

    Eureka 系列(03)Spring Cloud 自动装配原理 [TOC] 0. Spring Cloud 系列目录 - Eureka 篇 本文主要是分析 Spring Cloud 是如何整合 Eu ...

  7. Spring Boot系列(二):Spring Boot自动装配原理解析

    一.Spring Boot整合第三方组件(Redis为例) 1.加依赖 <!--redis--> <dependency> <groupId>org.springf ...

  8. Spring Boot 自动装配原理

    Spring Boot 自动装配原理 Spring Boot 在启动之前还有一系列的准备工作,比如:推断 web 应用类型,设置初始化器,设置监听器,启动各种监听器,准备环境,创建 applicati ...

  9. SpringBoot:带你认认真真梳理一遍自动装配原理

    前言 Spring翻译为中文是“春天”,的确,在某段时间内,它给Java开发人员带来过春天,但是随着我们项目规模的扩大,Spring需要配置的地方就越来越多,夸张点说,“配置两小时,Coding五分钟 ...

随机推荐

  1. scrapy使用response.body时编码问题

    scrapy使用response.body时编码问题 摘要:scrapy使用response.body时编码问题.如果在使用responses.body获取数据时,需要将其编码转换成unicode,即 ...

  2. TensorFlow常用Python扩展包

    TensorFlow常用Python扩展包 TensorFlow 能够实现大部分神经网络的功能.但是,这还是不够的.对于预处理任务.序列化甚至绘图任务,还需要更多的 Python 包. 下面列出了一些 ...

  3. MinkowskiEngine实用函数和类

    MinkowskiEngine实用函数和类 sparse_quantize MinkowskiEngine.utils.sparse_quantize(coords, feats=None, labe ...

  4. 英特尔 i5-9400F,或将成为本年最高性价比的游戏处理器

    英特尔 i5-9400F,或将成为本年最高性价比的游戏处理器 一直以来,每一代英特尔 i5 系列都是很多游戏玩家主要的选购对象,它和任何一款显卡似乎都能够很好的搭配起来.可凡事都有美中不足的地方,比如 ...

  5. Django框架之路由层汇总

    一 Django中路由的作用 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:你就是以这种方式告诉Django,对于客户端发来 ...

  6. 0算法基础学算法 搜索篇第二讲 BFS广度优先搜索的思想

    dfs前置知识: 递归链接:0基础算法基础学算法 第六弹 递归 - 球君 - 博客园 (cnblogs.com) dfs深度优先搜索:0基础学算法 搜索篇第一讲 深度优先搜索 - 球君 - 博客园 ( ...

  7. 一文带你了解.Net自旋锁

    本文主要讲解.Net基于Thread实现自旋锁的三种方式 基于Thread.SpinWait实现自旋锁 实现原理:基于Test--And--Set原子操作实现 使用一个数据表示当前锁是否已经被获取 0 ...

  8. 【NX二次开发】Block UI 多行字符串

    属性说明 常规         类型 描述     BlockID     String 控件ID     Enable     Logical 是否可操作     Group     Logical ...

  9. NX二次开发】Block UI 选择特征

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  10. 『心善渊』Selenium3.0基础 — 5、XPath路径表达式详细介绍

    目录 1.XPath介绍 2.什么是XML 3.XML与HTML对比 4.为什么使用XPath定位页面中的元素 5.XPath中节点之间的关系 (1)节点的概念 (2)节点之间的关系类型 6.XPat ...