看看SpringBoot的自动装配原理

2024-09-02 03:28

本文主要是介绍看看SpringBoot的自动装配原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

SpringBoot的自动装配原理

明天面试浅浅复习一下八股文

面试官:说一下springboot的自动装配

像以前开发的时候,配置文件需要用xml和java配置类进行显式配置,一整就整一大堆的配置文件

then 什么是自动装配?

Spring boot 定义了一套自己的规范,在Spring Boot启动的时候会扫描有什么外部的jar包的META-INF/spring.factories,然后加载里面的配置文件到Spring里面,像那些自己写的starter就只需要按照Spring boot定的规则定义文件就行了。

简单理解就是自动装配就是通过一些注解和一些简单的配置就可以在Spring boot中使用第三方的某些功能。

如何实现自动装配?

自动装配的核心就是@SpringBootApplication

打开这个类look look,这个版本是3.x的SpringBoot

更新太快了,刚刚才开始摸两下java11,3.x的spirng就需要java17只吃了,卷烂了卷烂了

SpringBootApplication.java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 这个在下面再拉出来拷打一下
@EnableAutoConfiguration // 这个注解用来启动自动装配,下面展开
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) // 这个玩意就是扫包的,扫描那些有标注@Component的包,通过定义不扫什么包,比如这个excludeFilters玩意就是用来定义不扫什么包的
public @interface SpringBootApplication

@SpringBootConfiguration

Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration // 注明这个也是个配置类
@Indexed // 作为元注解声明注解,可以减少应用启动的速度,下面稍微展开一下
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}

@Indexed:当Spring Boot需要扫描的类太多的时候,@ComponentScan就是这个类需要扫描的类太多的时候,应用启动的时间就会变长。这个注解的用处就是用来解决这个问题的,再项目进行编译打包的时候,会自动生成被@Indexed注释的类的解析结果的文件META-INF/spring.components,当Spring开始进行上下文扫描的的时候,会直接读取被@Indexed处理的文件而不需要进行扫描,这样就可以减少应用的启动时间。

@EnableAutoConfiguration:实现自动装配的核心注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 将main包下面的包注册到容器中
@Import(AutoConfigurationImportSelector.class) // 加载需要自动装配的类
public @interface EnableAutoConfiguration {/*** Environment property that can be used to override when auto-configuration is* enabled.*/String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";/*** Exclude specific auto-configuration classes such that they will never be applied.* @return the classes to exclude*/Class<?>[] exclude() default {};/*** Exclude specific auto-configuration class names such that they will never be* applied.* @return the class names to exclude* @since 1.3.0*/String[] excludeName() default {};}

还需要继续深入看看这个AutoConfigurationImportSelector.class

// 继承体系
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered // DeferredImportSelector 这个玩意继承了一个叫 ImportSelector的接口
public interface DeferredImportSelector extends ImportSelector // 然后我们现在回到AutoConfigurationImportSelector这个类中,有点混乱了写的
public String[] selectImports(AnnotationMetadata annotationMetadata) {// 判断自动装配是否打开,简单的理解为上面的EnableAutoConfiguration注解if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {// 然后获取需要装配的bean,这个this.getAutoConfigurationEntry是主要负责加载自动配置类的,主要就是获取所有的自动装配的类,然后从上面也有提过的`META-INF/spring.factories`来加载配置类AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}}

这个方法主要是读取所有符合Spring Boot加载条件的的类名,然后把这些类加载到IoC容器中。

文字总结一下,这个大致的流程

  1. 先在AutoConfigurationImportSelector判断自动装配开关是否打开(spring.boot.enableautoconfiguration=true
  2. 然后去获取用于EnableAutoConfiguration注解中的 exclude 和 excludeName。这个exclude都是在AnnoctionAttribuite的两个key
  3. 然后再去加载META-INF/spring.factories,XXXAutoConfiguration的作用就是按需加载组件。(在idea的项目文件树中,有一个目录叫做External Libraries,打开里面的目录可以看到会有一个spring.factories的文件的,里面会有一些配置的信息)
  4. 在这些文件里面会有很多个配置文件,他们并不会全部一次加载,加载的时候会有一个筛选的方法,这个注解叫@ConditionalOnClass(以后再看看这个东西怎么个回事,懒惰了不看了)

以前有个面试官问过我,如何实现一个starter?顺手也总结一下

  1. 首先要创建一个工程,取个名字 test-spring-boot-starter
  2. 然后这个工程要是一个maven的工程,或者说是gradle也行,引入关于Spring Boot的相关依赖

pom文件的伪代码

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>${挑选适合你的版本}</version></dependency>
</dependencies>
  1. 然后这个时候,创建一个xxxxAutoConfiguration
  2. 紧接着需要再这个工程下面,创建一个上面提了很多次的spring.factories,需要有这个玩意才能扫到你。(哦还需要一个META-INF做目录)
  3. 然后就可以测试一下了,随便创建一个新的工程,然后在你的pom文件里加入一个引入一个starter
<dependencies><dependency><groupId>org.mtc.test</groupId><artifactId>test-spring-boot-starter</artifactId><version>${你maven创建的时候自己设置的版本}</version></dependency>
</dependencies>

这就ok了

再一个大的总结

主要的核心就是扫描配置就是基于Spring factories,这个四舍五入等于事先约定好的配置文件,也就是Spring Boot所说的约定大于配置,不需要在通过xml进行配置。

@EnableAutoConfiguration 开启自动装配

自动配置类根据@Conditional来进行筛选按需加载

然后通过引入(eg. pom)的形式来使用

done

这篇关于看看SpringBoot的自动装配原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1128862

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2