从源码分析Springboot自动配置原理

news2024/11/24 17:45:42

一、什么是Springboot的自动配置

Spring Boot自动配置(Auto-configuration)是Spring Boot框架的核心特性之一,它使得开发者可以更容易地创建基于Spring的应用程序,而无需进行大量的手动配置。自动配置基于开发者添加的jar依赖项来自动配置Spring应用程序。

二、核心原理

  • 依赖管理:Spring Boot通过Maven或Gradle等构建工具管理项目的依赖关系。当开发者在项目中添加了某个Spring Boot Starter依赖时,Spring Boot会尝试自动配置与该依赖相关的bean。
  • 条件化配置:Spring Boot使用条件注解(如@ConditionalOnClass@ConditionalOnProperty等)来决定是否应该创建和配置某个bean。这些条件注解可以根据类路径上的类是否存在、某个配置属性是否存在或具有特定值等条件来触发自动配置。
  • 默认配置:对于许多常见的配置项,Spring Boot提供了默认值。如果开发者没有提供自定义的配置,那么这些默认值将被使用。

三、实现方式

  • @SpringBootApplication:这是Spring Boot应用程序的入口点。该注解是@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan的组合。其中,@EnableAutoConfiguration注解启用了自动配置功能。
  • META-INF/spring.factories:Spring Boot在启动时会加载META-INF/spring.factories文件,该文件包含了自动配置类的列表。Spring Boot会遍历这些自动配置类,并根据条件注解来决定是否创建和配置相应的bean。
  • Starters:Spring Boot提供了许多Starters,它们是一组方便的依赖描述符,用于简化Maven或Gradle构建文件的依赖管理。每个Starter都包含了一组用于支持特定功能的依赖项和自动配置。

四、自定义配置

  • application.properties或application.yml:开发者可以在src/main/resources目录下提供application.propertiesapplication.yml文件来覆盖自动配置的默认值。这些文件通常用于定义应用程序的特定配置。
  • @Configuration和@Bean:如果自动配置不满足需求,开发者可以编写自己的@Configuration类,并使用@Bean注解来定义和配置自己的bean。这些自定义配置将覆盖自动配置的相同bean。

五、调试和禁用自动配置

  • debug属性:在application.propertiesapplication.yml文件中设置debug=true可以启用自动配置的调试日志,以帮助开发者了解哪些自动配置被应用以及为什么。
  • exclude属性:使用@SpringBootApplication@EnableAutoConfiguration注解的exclude属性可以排除特定的自动配置类。这允许开发者禁用不需要的自动配置。

六、从源码分析springboot自动配置原理

下图为springboot项目的启动类;启动类上面使用了@SpringBootApplication注解

进入该注解查看

/*
 * Copyright 2012-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;

/**
 * Indicates a {@link Configuration configuration} class that declares one or more
 * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration
 * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience
 * annotation that is equivalent to declaring {@code @Configuration},
 * {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
 *
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @since 1.2.0
 */
@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) })
public @interface SpringBootApplication {

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	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
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	/**
	 * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
	 * for a type-safe alternative to String-based package names.
	 * @return base packages to scan
	 * @since 1.3.0
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	/**
	 * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
	 * scan for annotated components. The package of each class specified will be scanned.
	 * <p>
	 * Consider creating a special no-op marker class or interface in each package that
	 * serves no purpose other than being referenced by this attribute.
	 * @return base packages to scan
	 * @since 1.3.0
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

}

可以看出@SpringBootApplication注解由以下注解实现

下面对以上注解进行介绍:

  1. @Target(ElementType.TYPE):
    • 这是一个元注解,用于指定它所修饰的注解(在本例中是@SpringBootApplication)可以应用于哪些Java元素。ElementType.TYPE表示这个注解只能应用于类、接口(包括注解类型)或枚举声明。
  2. @Retention(RetentionPolicy.RUNTIME):
    • 这也是一个元注解,用于指定它所修饰的注解(@SpringBootApplication)的生命周期。RetentionPolicy.RUNTIME表示这个注解不仅被保留在编译后的class文件中,而且在运行时可以通过反射获取到。
  3. @Documented:
    • 这个注解表示被它修饰的注解(@SpringBootApplication)应该被Javadoc和类似的工具记录。换句话说,如果你在类上使用了@SpringBootApplication注解,并且为该类生成了Javadoc文档,那么这个注解也会出现在Javadoc文档中。
  4. @Inherited:
    • 表示如果一个类使用了这个注解(@SpringBootApplication),那么它的子类会自动继承这个注解,除非子类明确地使用@SpringBootApplication(false)来关闭继承。然而,在@SpringBootApplication这个场景下,由于它通常用于主应用类,并且这个类通常不会被子类继承,所以@Inherited在这里的实际作用并不明显。
  5. @SpringBootConfiguration:
    • 表明该类是一个Spring Boot的配置类,即它使用Java配置的方式来替代传统的XML配置文件。在Spring Boot中,这个注解其实就是一个@Configuration注解的特化版本,专门用于Spring Boot应用。
  6. @EnableAutoConfiguration:
    • 这是Spring Boot的核心注解之一。它告诉Spring Boot根据添加的jar包依赖(即Starters)来自动配置你的应用。例如,如果你添加了spring-boot-starter-web依赖,Spring Boot会自动配置嵌入式Tomcat、Spring MVC等。此外,你还可以通过spring.factories文件和@SpringBootApplicationexclude属性来定制或关闭某些自动配置。
  7. @ComponentScan(excludeFilters = {...}):
    • 告诉Spring Boot在哪些包中查找被@Component@Service@Repository@Controller等注解标记的类,并把它们注册为Spring Bean。excludeFilters属性用于指定要排除的类或包。在这个例子中,TypeExcludeFilterAutoConfigurationExcludeFilter是自定义的过滤器,用于在组件扫描时排除特定的类或包。

    • TypeExcludeFilter通常用于排除某些特定类型的组件(如某些接口的实现类)。

    • AutoConfigurationExcludeFilter则是Spring Boot特有的过滤器,用于排除Spring Boot的自动配置类。这是通过spring.autoconfigure.exclude属性或在@SpringBootApplication注解中指定的排除类来实现的。

上述注解中,前四个都是元注解,与自动配置无关。@ComponentScan注解用于包扫描,也与自动配置无关;@SpringBootConfiguration注解用于声明是一个配置类,也与springboot的自动配置无关。所以与springboot自动配置相关的注解就是@EnableAutoConfiguration了。其实从注解的名称也可以看出来,@EnableAutoConfiguration注解是用于启用自动配置的注解。点进@EnableAutoConfiguration查看该注解。

前面四个注解为元注解,不用看,下面将先讲解@AutoConfigurationPackage注解和@Import注解的使用。

 

@AutoConfigurationPackage注解在Spring Boot中扮演着重要的角色,其作用主要可以归纳为以下几点:

  1. 自动配置包
    • @AutoConfigurationPackage注解的主要作用是将主程序类(通常是带有@SpringBootApplication注解的类)所在的包及所有子包下的组件扫描到Spring容器中。这意味着这些包下的类如果使用了如@Service@Controller@Repository等注解,它们将会被自动注册为Spring的Bean。
  2. 作为组合注解的一部分
    • @AutoConfigurationPackage注解通常不是直接使用的,而是作为@SpringBootApplication注解的一部分。具体来说,@SpringBootApplication注解包含了@EnableAutoConfiguration注解,而@EnableAutoConfiguration又进一步包含了@AutoConfigurationPackage。因此,当开发者在Spring Boot的主类上添加@SpringBootApplication注解时,就间接地启用了@AutoConfigurationPackage的功能。
  3. 包路径的确定
    • Spring Boot会自动确定@SpringBootApplication(或带有@EnableAutoConfiguration的类)所在的包路径,并将其作为自动配置的基准包。然后,这个基准包及其所有子包下的组件都会被扫描并注册到Spring容器中。
  4. 附加其他路径
    • 虽然@AutoConfigurationPackage默认扫描主程序类所在的包及所有子包,但开发者也可以通过额外的配置来指定其他的包路径。不过,这通常不是通过直接修改@AutoConfigurationPackage来实现的,而是通过其他方式,如@ComponentScan注解或Spring Boot的配置文件。
  5. 与Spring Boot的自动配置机制相结合
    • @AutoConfigurationPackage与Spring Boot的自动配置机制紧密结合。当Spring Boot启动时,它会根据添加的依赖和其他配置信息来自动配置应用程序。这个过程中,@AutoConfigurationPackage确保了需要的组件都能够被Spring容器正确地管理和使用。

 @AutoConfigurationPackage注解的主要作用是将主程序类所在的包及所有子包下的组件扫描到Spring容器中,也与自动配置关系不大。下面我们了解一下。

@Import注解在Spring框架中主要用于将指定的类、配置类或组件导入到Spring的Inversion of Control(IOC)容器中,以实现这些类、配置类或组件的自动配置和管理。其作用具体可以归纳为以下几点:

  1. 导入配置类或组件
    • @Import注解允许开发者直接导入一个或多个配置类(带有@Configuration注解的类)或组件类到Spring IOC容器中。这样,这些类中的Bean定义或组件就能被Spring容器管理和自动装配到其他Bean中。
  2. 支持多种导入方式
    • @Import注解支持多种导入方式,包括直接导入类、通过实现ImportSelector接口动态选择类进行导入,以及通过实现ImportBeanDefinitionRegistrar接口自定义Bean的注册过程。

    • 直接导入类:使用@Import的value属性,传入一个或多个Class<?>类型的数组,Spring将自动将这些类作为Bean注册到IOC容器中。

    • 使用ImportSelector:开发者可以实现ImportSelector接口,并重写selectImports方法,根据需求动态返回需要导入的类的全类名数组。

    • 使用ImportBeanDefinitionRegistrar:开发者可以实现ImportBeanDefinitionRegistrar接口,并重写registerBeanDefinitions方法,以自定义Bean的注册逻辑。

  3. 支持导入普通类
    • 在Spring 4.2及之后的版本中,@Import注解还支持导入普通的Java类(非配置类)。这些普通类在导入后也会被Spring容器管理,并可以通过@Autowired等方式进行自动装配。
  4. 与@Configuration结合使用
    • @Import注解经常与@Configuration注解结合使用,用于在配置类中导入其他配置类或组件。这使得配置类能够模块化地组织和管理Bean定义,提高代码的可读性和可维护性。
  5. 自定义Bean名称
    • 当使用ImportBeanDefinitionRegistrar方式导入类时,开发者可以自定义Bean在容器中的名称。这对于需要控制Bean名称的场景非常有用。
  6. 与Spring Boot自动配置结合
    • 在Spring Boot中,@Import注解与自动配置机制结合紧密。许多自动配置类都通过@Import注解来导入其他配置类或组件,以实现自动配置的功能

 @Import注解允许开发者直接导入一个或多个配置类或组件类到Spring IOC容器中。所以我们查看一下导入的类AutoConfigurationImportSelector.class

该类实现了DeferredImportSelector接口,而DeferredImportSelector又是ImportSelector的子接口

 ImportSelector接口:里面有一个String[] selectImports(AnnotationMetadata var1);方法

所以 AutoConfigurationImportSelector类必然也实现了这个方法

  • selectImports方法允许开发者根据自定义的逻辑来动态选择配置类。它返回一个字符串数组,数组中的每个元素都是配置类的全限定类名。

 该类返回StringUtils.toStringArray(autoConfigurationEntry.getConfigurations())

所以我们查看autoConfigurationEntry是如何获取的,即查看getAutoConfigurationEntry方法

该方法返回new AutoConfigurationEntry(configurations, exclusions);

所以我们查看configurations是如何来的,即查看getCandidateConfigurations方法

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.

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.");

翻译这段英文

在META-INF/spring.factores中找不到自动配置类。如果你
正在使用自定义包装,请确保该文件正确无误。

所以 META-INF/spring.factores里面装的就是需要springboot自动配置的类

我们找一个依赖查看下面有没有META-INF/spring.factores这个文件,这个文件里面的内容是类的全限定名。

随便找一个类点进去,这个类是一个配置类,里面有方法上面使用@Bean注解,使用了@Bean注解,方法的返回值就会交给Spring IOC管理

 

提问:META-INF/spring.factores文件里面所有的类都交给Spring IOC了吗

答案:不是

比如上图中和Bean一起使用的还有注解@ConditionalOnMissingBean,需要满足条件才会交给Spring管理。

  • 当在配置类或组件类上标注了@ConditionalOnMissingBean注解时,Spring Boot会检查容器中是否已存在指定类型的Bean。
  • 如果不存在,则会根据@ConditionalOnMissingBean的配置来决定是否创建一个新的Bean实例并加入到容器中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1879582.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nuxt3 的生命周期和钩子函数(六)

title: Nuxt3 的生命周期和钩子函数&#xff08;六&#xff09; date: 2024/6/30 updated: 2024/6/30 author: cmdragon excerpt: 摘要&#xff1a;本文深入解析了Nuxt3框架中的多个核心生命周期钩子和组件注册功能&#xff0c;包括imports:sources、imports:extend、import…

【Qt】之【Bug】大量出现“未定义的标识符”问题

背景 构建时出现大量错误 原因 中文注释问题 解决 方法1. 报错代码附近的中文注释全部删掉。。。 方法2. 报错的文件添加 // Chinese word comment solution #pragma execution_character_set("utf-8")

2024年【安全生产监管人员】考试资料及安全生产监管人员考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全生产监管人员考试资料是安全生产模拟考试一点通生成的&#xff0c;安全生产监管人员证模拟考试题库是根据安全生产监管人员最新版教材汇编出安全生产监管人员仿真模拟考试。2024年【安全生产监管人员】考试资料及…

算法力扣刷题 二十六【459.重复的子字符串】

前言 字符串篇&#xff0c;继续。 记录 二十六【459.重复的子字符串】 一、题目阅读 给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例…

录取查询怎么公布?

这篇文章对于教育工作者来说非常有用&#xff0c;提供了关于如何公布学生录取情况的多种方法和注意事项。以下是对您文章的一些补充和建议&#xff1a; 1.易查分的使用&#xff1a;易查分系统是一个很好的工具&#xff0c;特别是对于那些不擅长技术开发的老师。它简化了查询过程…

40 - 餐馆营业额变化增长(高频 SQL 50 题基础版)

40 - 餐馆营业额变化增长 -- 方法一 SELECT t.visited_on,sum(c.amount) amount,ROUND(sum(c.amount) / 7, 2) average_amount FROM customer c,-- 查出足够7天的数据日期(SELECT DISTINCT visited_onFROM customerWHERE visited_on >(SELECT ADDDATE(MIN(visited_on), 6) F…

Nginx-2

一、高级配置 1.1网页状态页 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module&#xff0c;否则配置完成之后监测会是提示语法错误注意: 状态页显示的是整个服务器的状态,而非虚拟主机的状…

半个月从几十升粉到500(发红包喽)

目录 1. 背景2. 涨粉秘籍2.1 持续创作高质量内容2.1.1 保持频率2.1.2 技术文章为主2.1.3 图文并茂 2.2 积极参与社区活动2.2.1 社区分享2.2.2 发文活动 2.3 互动与建立信任2.3.1 与读者互动2.3.2 红包互动2.3.3 动态分享 2.4 标题与内容的优化2.4.1 标题吸引2.4.2 内容实用 2.5…

高效办公秘诀:使用Excel超级处理器提高工作效率,提升职场竞争力

在现今快节奏的工作环境中&#xff0c;如何高效地完成工作任务&#xff0c;减少加班时间&#xff0c;成为了许多职场人士关注的焦点。其中&#xff0c;Excel作为一款功能强大的电子表格软件&#xff0c;被广泛应用于数据处理、分析以及报表制作等领域。然而&#xff0c;仅仅依赖…

C++ sizeof的各种

C sizeof的各种 1. 含有虚函数的类对象的空间大小2. 虚拟继承的类对象的空间大小3. 普通变量所占空间大小4. 复合数据类型&#xff08;结构体和类&#xff09;5. 数组6. 类型别名7. 动态分配内存8. 指针9. 静态变量10. 联合体11. 结构体使用#program pack 1. 含有虚函数的类对象…

Linux多进程和多线程(三)进程间通讯-信号处理方式和自定义处理函数

进程间通信之信号 信号信号的种类 信号在操作系统中的定义如下: 信号的处理流程在 Linux 中对信号的处理⽅式 自定义信号处理函数 信号的发送 kill() 函数:raise() 函数: 示例 : 创建⼀个⼦进程&#xff0c;⼦进程通过信号暂停&#xff0c;⽗进程发送 终⽌信号等待信号 pause()…

mysql解压版本安装5.7

1. 官网下载好解压版本 我这边5.7版本 https://dev.mysql.com/downloads/file/?id523570 mysql官网 创建 my.ini文件 内容如下 [client] #客户端设置&#xff0c;即客户端默认的连接参数# socket /data/mysqldata/3306/mysql.sock #用于本地连接的socket套接字 # 默…

Nginx和CDN运用

一.Web缓存代理 1.工作机制 代替客户机向网站请求数据&#xff0c;从而可以隐藏用户的真实IP地址。将获得的网页数据&#xff08;静态Web元素&#xff09;保存到缓存中并发送给客户机&#xff0c;以便下次请求相同的数据时快速响应。 2.代理服务器的概念 代理服务器是一个位…

YOLOv8目标检测在RK3588部署全过程

一&#xff0c;前言 这是一个关于从电脑安装深度学习环境到实现YOLOv8目标检测在RK3588上部署的全过程。 本人配置&#xff1a; 1&#xff0c;一台笔记本 2&#xff0c;一个香橙派5s 二&#xff0c;深度学习环境配置 2.1 安装anaconda 使用清华镜像源下载https://mirror…

内容营销专家刘鑫炜:说真的,我写文章可不是为了流量!

今天&#xff0c;打开某号后台&#xff0c;发现我的号一夜之间加了几十个粉丝&#xff0c;确实有些意外。 说真的&#xff0c;我写文章的目的真不是为了流量。 在这个被大数据和算法统治的时代&#xff0c;我们常常听到这样的声音&#xff1a;“流量就是一切”。然而&#xff…

对原生input加上:当前输入字数/最大输入字数

源码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>/* 样式…

【解释】i.MX6ULL_IO_电气属性说明

【解释】i.MX6ULL_IO_电气属性说明 文章目录 1 Hyst1.1 迟滞&#xff08;Hysteresis&#xff09;是什么&#xff1f;1.2 GPIO的Hyst. Enable Field 参数1.3 应用场景 2 Pull / Keep Select Field2.1 PUE_0_Keeper — Keeper2.2 PUE_1_Pull — Pull2.3 选择Keeper还是Pull 3 Dr…

深圳制作网站价格怎么样

深圳是中国的经济特区&#xff0c;也是中国最具活力和创新情商的城市之一。随着互联网的普及&#xff0c;越来越多的企业和个人开始意识到拥有一个优质的网站对于提升品牌形象、销售产品和服务、吸引客户等方面的重要性。因此&#xff0c;制作网站成为了一项必不可少的工作。 深…

Linux常见操作问题

1、登录刚创建的用户&#xff0c;无法操作。 注&#xff1a;etc/passwd文件是Linux操作系统中存储用户账户信息的文本文件&#xff0c;包含了系统中所有用户的基本信息&#xff0c;比如用户名、用户ID、用户组ID、用户家目录路径。 注&#xff1a;etc: 这个目录存放所有的系统…

网络----头部

TCP IP UDP udp头部 帧 http 连接 MSS和MTU 图片来源