栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Boot自动装配(必面问题详解)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Boot自动装配(必面问题详解)

Spring Boot自动装配(必面问题详解)

1. 什么是自动装配2. 自动装配原理3. 核心类分析4. 核心总结

本文基于Spring Boot 2.6.3,在文章最后总结了面试回答的核心要点。

1. 什么是自动装配

我们在使用Spring Boot的时候,会自动将Bean装配到IoC容器中。例如我们在使用Redis数据库的时候,会引入依赖spring-boot-starter-data-redis。在引入这个依赖后,服务初始化的时候,会将操作Redis需要的组件注入到IoC容器中进行后续使用。自动装配大致过程如下:

(1)获取到组件(例如spring-boot-starter-data-redis)meta-INF文件夹下的spring.factories文件。
(2)spring.factories文件中列出需要注入IoC容器的类。
(3)将实体类注入到IoC容器中进行使用。

2. 自动装配原理

上一章中的大致流程,是通过@SpringBootApplication进行实现。这个注解声明在Spring Boot的启动类上。

@SpringBootApplication
public class DailySpringApplication {
    public static void main(String[] args) {
        SpringApplication.run(DailySpringApplication.class, args);
    }
}

点击进入@SpringBootApplication注解,其中通过@EnableAutoConfiguration注解实现了自动装配。

@Target({ElementType.TYPE}) // 该注解作用于接口、类、枚举
@Retention(RetentionPolicy.RUNTIME) // 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@documented // 有了该注释后,如果有接口使用了该注解,生成的javadoc文件中,会把该注解展示出来
@Inherited // 如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解
@SpringBootConfiguration // 标识它是一个Spring Boot配置类
@EnableAutoConfiguration // 主要是通过这个注解实现自动装配
@ComponentScan(  // 配置类上添加 @ComponentScan 注解。该注解默认会扫描该类所在的包下所有的配置类
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

点击进入@EnableAutoConfiguration注解,AutoConfigurationPackage的作用是记录使用了该注释的类所在的包以及子包的路径,以便后序读取,可以参考这篇文章。其中,最重要的是AutoConfigurationimportSelector.class,将需要装配的类装配到IoC容器中,下面我们重点分析一下这个类的实现。

@Target({ElementType.TYPE}) // 该注解作用于接口、类、枚举
@Retention(RetentionPolicy.RUNTIME) // 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@documented // 有了该注释后,如果有接口使用了该注解,生成的javadoc文件中,会把该注解展示出来
@Inherited // 如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解
@AutoConfigurationPackage // 记录使用了该注释的类所在的包以及子包的路径,以便后序读取
@import({AutoConfigurationimportSelector.class})
public @interface EnableAutoConfiguration{...}
3. 核心类分析

AutoConfigurationimportSelector中的selectimport是自动装配的核心实现,它主要是读取meta-INF/spring.factories文件,经过去重、过滤,返回需要装配的配置类集合。

public String[] selectimports(Annotationmetadata annotationmetadata) {
        if (!this.isEnabled(annotationmetadata)) {
            return NO_importS;
        } else {
            AutoConfigurationimportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationmetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

我们点进getAutoConfigurationEntry()方法:

getAttributes获取@EnableAutoConfiguration中的exclude、excludeName等。getCandidateConfigurations获取所有自动装配的配置类,也就是读取spring.factories文件,后面会再次说明。removeDuplicates去除重复的配置项。getExclusions根据@EnableAutoConfiguration中的exclude、excludeName移除不需要的配置类。fireAutoConfigurationimportEvents 广播事件

最后根据多次过滤、判重返回配置类合集。

protected AutoConfigurationimportSelector.AutoConfigurationEntry getAutoConfigurationEntry(Annotationmetadata annotationmetadata) {
        if (!this.isEnabled(annotationmetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationmetadata); 
            List configurations = this.getCandidateConfigurations(annotationmetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set 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);
        }
    }

我们点进getCandidateConfigurations()方法,这里通过loadFactoryNames方法,扫描classpath下的meta-INF/spring.factories文件,里面是以key=value形式存储,我们读取其中key=EnableAutoConfiguration,value就是需要装配的配置类,也就是getCandidateConfigurations返回的值。

protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {
     List 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;
}
4. 核心总结

(1)通过注解@SpringBootApplication=>@EnableAutoConfiguration=>@import({AutoConfigurationimportSelector.class})实现自动装配。
(2)AutoConfigurationimportSelector类中重写了importSelector中selectimports方法,批量返回需要装配的配置类。
(3)通过Spring提供的SpringFactoriesLoader机制,扫描classpath下的meta-INF/spring.factories文件,读取需要自动装配的配置类。
(4)依据条件筛选的方式,把不符合的配置类移除掉,最终完成自动装配。


Ref:
1.《Spring Cloud Alibaba 微服务原理与实战》谭锋
2.《Spring 5 核心原理与30个类手写实战》谭勇德

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/726580.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号