Mushroom Notes Mushroom Notes
🍄首页
  • JavaSE

    • 基础篇
    • 数据结构
    • IO流
    • Stream流
    • 函数式接口
    • JUC
    • 反射
    • 网络编程
    • 设计模式
  • JavaEE

    • Servlet
    • JDBC
    • 会话技术
    • 过滤器监听器
    • 三层架构
  • JDK

    • 总览
  • JVM

    • 总览
  • 常用mate
  • CSS
  • JavaScript
  • rds 数据库

    • MySQL
    • MySQL 进阶
    • MySQL 库表规范
  • nosql 数据库

    • Redis
    • Redis 进阶
    • Redis 底层
    • MongoDB
  • Spring生态

    • Spring
    • Spring MVC
    • Spring boot
    • Spring Validation
  • Spring Cloud生态

    • Spring Cloud
    • 服务治理
    • 远程调用
    • 网关路由
    • 服务保护
    • 分布式事务
    • 消息中间件
  • 数据库

    • Mybatis
    • Mybatis Plus
    • Elasticsearch
    • Redisson
  • 通信

    • Netty
📚技术
  • 方案专题
  • 算法专题
  • BUG专题
  • 安装专题
  • 网安专题
  • 面试专题
  • 常用网站
  • 后端常用
  • 前端常用
  • 分类
  • 标签
  • 归档

kinoko

一位兴趣使然的热心码农
🍄首页
  • JavaSE

    • 基础篇
    • 数据结构
    • IO流
    • Stream流
    • 函数式接口
    • JUC
    • 反射
    • 网络编程
    • 设计模式
  • JavaEE

    • Servlet
    • JDBC
    • 会话技术
    • 过滤器监听器
    • 三层架构
  • JDK

    • 总览
  • JVM

    • 总览
  • 常用mate
  • CSS
  • JavaScript
  • rds 数据库

    • MySQL
    • MySQL 进阶
    • MySQL 库表规范
  • nosql 数据库

    • Redis
    • Redis 进阶
    • Redis 底层
    • MongoDB
  • Spring生态

    • Spring
    • Spring MVC
    • Spring boot
    • Spring Validation
  • Spring Cloud生态

    • Spring Cloud
    • 服务治理
    • 远程调用
    • 网关路由
    • 服务保护
    • 分布式事务
    • 消息中间件
  • 数据库

    • Mybatis
    • Mybatis Plus
    • Elasticsearch
    • Redisson
  • 通信

    • Netty
📚技术
  • 方案专题
  • 算法专题
  • BUG专题
  • 安装专题
  • 网安专题
  • 面试专题
  • 常用网站
  • 后端常用
  • 前端常用
  • 分类
  • 标签
  • 归档
  • 方案专题

  • 算法专题

  • BUG专题

  • 安装专题

  • 网安专题

  • 面试专题

    • Java 基础篇
    • JUC篇
    • JVM篇
    • SSM篇
    • Springboot篇
      • Spring boot自动配置原理
      • 自动配置的实现流程
      • 在SpringBot项目中如何让一个Bean放到IOC容器?
    • SpringCloud篇
    • MQ篇
    • MySQL篇
    • Redis篇
    • 设计模式篇
    • Elasticsearch篇
  • 专题
  • 面试专题
kinoko
2023-12-26
目录

Springboot篇面试题

# Spring boot自动配置原理


spring boot提供了众多的启动器,如spring-boot-starter-xxx
image.png
官方启动器介绍: https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/using-boot-build-systems.html##using-boot-starter (opens new window)

Spring Boot启动器的作用

  • 配置一个启动器它会把整合这个框架或模块的依赖全部导入。
  • 每一个启动器都有一个自动配置类,实现自动整合Spring。
  • 每一个启动器都有一个属性类,提供了默认的属性配置。

一切的自动配置,开始于启动类的main方法
image.png

特别的两个地方:

  • 注解: @SpringBootApplication 【重点】
  • run方法: SpringApplication.run() 运行spring应用(创建spring容器)

@SpringBootApplication 相当于三个注解的组合

  1. @SpringBootConfiguration 【作用: 定义配置类】
  2. @EnableAutoConfiguration 【作用: 启用自动配置】

注解@EnableAutoConfiguration,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcat、SpringMVC的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!

  1. @ComponentScan 【作用: 组件扫描】

配置组件扫描的指令。提供了类似与<context:component-scan>标签的作用 通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包

image.png
源码(其中以上三个注解起主要作用)

# 自动配置的实现流程

首先我们进入到@EnableAutoConfiguration中
image.png
这里主要做了两件事:

  1. 扫描需要自动配置的包,其实也就是启动类所在包及其子包
  2. 导入选中的自动配置类,这是最关键的

再进入到AutoConfigurationImportSelector,其中有一个方法叫selectImports,这个方法的作用是加载所有的自动配置类类名,放到一个String数组中,然后在启动类启动时,容器会初始化这个String数组中存在的所有自动配置类,然后这个方法中的getAutoConfigurationEntry()方法就是获取自动配置类类名的入口,通过这个入口获取自动配置类类名

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        // 创建自动配置类入口
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
        // 通过入口获取选择的自动配置类类名
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
    }
1
2
3
4
5
6
7
8
9
10

再进入到getAutoConfigurationEntry()方法中,其中有一个方法叫getCandidateConfigurations()这个方法就可以帮我们获取到一个候选的自动配置类类名的List集合

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);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

然后进到getCandidateConfigurations()方法中,我们可以看到一个SpringFactoriesLoader,Spring的工厂加载器,SpringApplication在运行Spring应用时,是通过SpringFactoriesLoader的loadSpringFactories()方法初始化Spring工厂实例的。

然后在执行getCandidateConfigurations()方法时,Spring的工厂加载器会去META-INF/spring.factories中获取需要自动加载的类,若没有获取到,则会报一个异常,告知没有需要自动配置的类。

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;
    }
1
2
3
4
5
6
7
8
9

再找到META-INF/spring.factories工厂配置文件
image.png
进入文件可以找到一个EnableAutoConfiguration的key,这个key所对应的值,就是所有的自动配置类,我们可以看到这个工厂配置文件中几乎候选了所有的自动配置类
image.png
可以在当前的jar包中找到这些自动配置类:
image.png
每个包都有一个XxxAutoConfiguration配置类,都是一个基于纯注解的配置类,是各种框架整合的代码。

那么这么多的配置类,是需要全部都创建出来吗?其实不然,只有当条件满足时,才会被创建,所以才说是候选的配置类,以RedisAutoConfiguration为例,只有当我们导入了Redis的起步依赖时,即导入了Redis的启动器时才会进行Redis自动配置类的创建
image.png
@EnableConfigurationProperties注解开启了该类的属性类,用于加载配置文件中的配置,每个启动器都带有一个自动配置类XxxAutoConfiguration以及属性类XxxProperties
image.png
从这个属性类中我们也可以看到存在很多默认的配置,这也是spring boot优化配置的体现。

面试话术 自动装配啊...有了解过,我记得大致的一个流程是这样的:
启动类在启动的时候会去加载@SpringbootApplication,这个注解也是自动装配的一个入口
然后@SpringbootApplication中有三个注解:@SpringConfigruation、@EnableAutoConfiguration 、@ComponentScan
@SpringConfigruation 是声明类是一个配置类
@ComponentScan 是扫描当前包下的所有组件,也就是启动类的自动扫包
@EnableAutoConfiguration 就是自动装配的一个核心注解了,然后里面有一个@Import 用来加载 AutoConfigurationImportSelect 这个类会读取springboot自动配置包中的META-INF的spring.factories文件
这个spring.factories文件包含一两百个SpringBoot写好的自动配置类,就是一个自动装配类的候选列表,当这些自动配置类达到一定条件时springboot就会去加载这些自动配置类,也就是自动配置类上@ConditionalOnClass这个注解,一般的话我们只要导了启动器依赖,就可以导到这个注解上的条件,然后这个自动配置类就会生效,配置类里的Bean就会被加载进IOC容器,我们就可以用了,以及我们yml的一些配置实际上都是在修改这个自动配置类的默认配置,就是覆盖掉默认配置,以yml的配置优先生效。

# 在SpringBot项目中如何让一个Bean放到IOC容器?


面试话术
有很多种方法,比如直接在Bean上面加@Component,让该Bean的包名在项目启动类同级或子级下。创建一个@Configuration配置类,然后通过@ComponentScan注解自行扫描Bean的目录,也可以直接在这个配置类里写一个方法,返回这个Bean对象,然后在方法上加个@Bean注解,甚至可以将这个配置类写到resources/META-INF/spring.factories文件中,加入springboot的自动装配列表。

#spring#java#springboot#面试
上次更新: 2023/12/29 11:32:56
SSM篇
SpringCloud篇

← SSM篇 SpringCloud篇→

最近更新
01
JVM 底层
09-13
02
JVM 理论
09-13
03
JVM 应用
09-13
更多文章>
Theme by Vdoing | Copyright © 2022-2024 kinoko | MIT License | 粤ICP备2024165634号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式