SpringBoot原理-03.自动配置-方案
一.自动配置原理
探究自动配置原理,就是探究spring是如何在运行时将要依赖JAR包提供的配置类和bean对象注入到IOC容器当中。我们当前准备一个maven项目itheima-utils,这里面定义了bean对象以及配置类,用来模拟第三方提供的依赖,首先进行导入。如果我们要使用这个第三方依赖,就要首先将其引入进来。
<dependency><groupId>com.example</groupId><artifactId>itheima-utils</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

我们在itheima-utils中可以发现,有一个配置类HeaderConfig,上面加上了一个注解@Configuration,表明当前类是一个配置类,里面有两个配置方法HeaderParser和HeaderGenerator,用来返回HeaderParser和HeaderGenerator的实例化对象,上面加上了@Bean注解,表明将这两个类作为IOC容器当中的bean对象。
package com.example;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class HeaderConfig {@Beanpublic HeaderParser headerParser(){return new HeaderParser();}@Beanpublic HeaderGenerator headerGenerator(){return new HeaderGenerator();}
}
package com.example;public class HeaderParser {public void parse(){System.out.println("HeaderParser ... parse ...");}}
package com.example;public class HeaderGenerator {public void generate(){System.out.println("HeaderGenerator ... generate ...");}}
我们还定义了一个普通类TokenParser,在该类上面加上了一个注解@Component。
package com.example;import org.springframework.stereotype.Component;@Component
public class TokenParser {public void parse(){System.out.println("TokenParser ... parse ...");}}
然后我们在springboot-web-config2中的pom文件中导入itheima-utils的依赖,然后在其测试类中编写测试代码,查看是否能够将IOC容器当中的bean对象引入进来。
package com.gjw.springbootwebconfig2;import com.example.HeaderGenerator;
import com.example.HeaderParser;
import com.example.TokenParser;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;@SpringBootTest
public class AutoConfigTests {@Autowiredprivate ApplicationContext applicationContext;// 测试第三方依赖下面的bean对象@Testvoid tokenParserTest() {System.out.println(applicationContext.getBean(TokenParser.class));}@Testvoid headerParserTest() {System.out.println(applicationContext.getBean(HeaderParser.class));}@Testvoid headerGeneratorTest() {System.out.println(applicationContext.getBean(HeaderGenerator.class));}
}
通过applicationContext这个IOC容器对象将TokenParser等bean对象引入进来,我们发现报错了,没有找到TokenParser这个bean对象
HeaderParser这个bean对象也没有找到。
那么为什么没有找到呢?
我们在类上加上了@Compoment注解来声明bean对象,这个注解就一定会生效么?并不是,这个注解还要被spring组件扫描到才行,而我们前面提到,在springboot项目当中,@SpringBootApplication具有包扫描的作用,但是其扫描范围仅仅是当前启动类所在包及其子包,也就是说根据当前的目录结构,他只会扫描com.gjw这个包下的类中定义的bean对象以及com.gjw这个包下子包中的类中定义的bean对象。

因此是扫描不到itheima-utils这个第三方依赖中所定义的bean对象的,所以找不到该bean对象。那么如何设置其扫描范围,让其扫描得到呢?
二.@ComponentScan组件扫描

我们可以在当前要运行的springboot项目的启动类上加上一个注解@ComponentScan来配置要扫描的范围。原来我们的扫描范围只是com.gjw,这是默认的。现在指定了要扫描com.example这个包,那么原来默认的包就要显式的指定出来。
在@ComponentScan这个注解当中我们可以通过value属性或者basePackages这个属性来指定我们要扫描哪些包?而这个属性返回值是一个数组,我们就在数组当中指定我们要扫描到的包是哪些。

package com.gjw;import ch.qos.logback.core.joran.event.SaxEvent;
import com.example.EnableHeaderConfig;
import com.example.HeaderConfig;
import com.example.MyImportSelector;
import com.example.TokenParser;
import org.dom4j.io.SAXReader;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;@ComponentScan({"com.gjw","com.example"}) // 方式一:采用@ComponentScan指定bean对象的扫描范围@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}
这样再次运行测试方法,发现已经成功获取到了IOC容器当中的bean对象。但是如果要扫描的包特别多,那么使用起来将非常繁琐,进而影响性能。
三.@Import导入

使用@Import导入主要的形式有三种:
1.导入普通类
2.导入配置类
3.导入ImportSelector接口实现类
我们依次来看
首先我们导入普通类,当前com.itheima这个包下有一个普通类TokenParser,上面加上了@Component注解,那么可以使用@Import注解将其导入。在@Import注解解释中如下。 
在@Import注解当中我们可以使用value属性导入一个常规类。也可以导入一个被@Configuration标识的配置类,也可以导入ImportSelector这个接口的实现类,还可以导入ImportBeanDefinitionRegistrar这个接口的实现类。
1.导入普通类
首先导入普通类TokenParser
package com.gjw;import ch.qos.logback.core.joran.event.SaxEvent;
import com.example.EnableHeaderConfig;
import com.example.HeaderConfig;
import com.example.MyImportSelector;
import com.example.TokenParser;
import org.dom4j.io.SAXReader;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;// @ComponentScan({"com.gjw","com.example"}) 方式一:采用@ComponentScan指定bean对象的扫描范围/*** 方式二:可以使用@Import注解* 可以用于:1.普通类* 2.配置类* 3.ImportSelector接口的实现类* 4.@EnableXXXX注解,封装@Import注解*/
@Import({TokenParser.class}) // 普通类
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}}
发现TokenParser这个类的bean对象已经存在。
2.导入配置类
然后我们导入配置类,
package com.gjw;import ch.qos.logback.core.joran.event.SaxEvent;
import com.example.EnableHeaderConfig;
import com.example.HeaderConfig;
import com.example.MyImportSelector;
import com.example.TokenParser;
import org.dom4j.io.SAXReader;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;// @ComponentScan({"com.gjw","com.example"}) 方式一:采用@ComponentScan指定bean对象的扫描范围/*** 方式二:可以使用@Import注解* 可以用于:1.普通类* 2.配置类* 3.ImportSelector接口的实现类* 4.@EnableXXXX注解,封装@Import注解*/
@Import({TokenParser.class}) // 普通类
@Import({HeaderConfig.class}) // 配置类@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}
打开测试类,在测试类当中运行测试方法,发现HeaderParser和HeaderGenerator的bean对象已经存在。
3.导入ImportSelector接口实现类

我们查看ImportSelector这个接口的源码。这个接口中有一个接口方法selectImports,返回值是一个String类型的数组,封装的是类名,封装的就是我们要将哪些类交给IOC容器管理,可以将这些类的全类名封装在数组中返回即可。
首先我们定义ImportSelector这个接口的实现类,
package com.example;import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;public class MyImportSelector implements ImportSelector {public String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.example.HeaderConfig"};}
}
既然selectImports这个方法中要的是全类名,那么我们可以将这些类定义到一个文件当中,要加载哪些类直接添加进去读取即可。读取之后封装到这个String数组中就行。这里我们指定将HeaderConfig这个类交给IOC容器管理。
然后我们使用@Import这个注解将其导入即可。
package com.gjw;import ch.qos.logback.core.joran.event.SaxEvent;
import com.example.EnableHeaderConfig;
import com.example.HeaderConfig;
import com.example.MyImportSelector;
import com.example.TokenParser;
import org.dom4j.io.SAXReader;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;// @ComponentScan({"com.gjw","com.example"}) 方式一:采用@ComponentScan指定bean对象的扫描范围/*** 方式二:可以使用@Import注解* 可以用于:1.普通类* 2.配置类* 3.ImportSelector接口的实现类* 4.@EnableXXXX注解,封装@Import注解*/
@Import({TokenParser.class}) // 普通类
@Import({HeaderConfig.class}) // 配置类
@Import(MyImportSelector.class) // MyImportSelector里面定义了要生成的bean对象
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}}
4.@EnableXxxx注解,封装@Import注解
但是如果基于上面的方式,以后我们在引入一个第三方依赖所提供的bean和配置类,每一次都要知道我们要引入哪些bean和配置类。但是我们知道吗?不知道,只有第三方依赖最清楚。常见的方案是第三方依赖会给我们提供一个注解,这个注解一般都是@Enable打头,注解中封装的就是@Import注解。在@Import后面再指定要导入哪些bean和配置类。
如itheima-utils依赖中就提供了@EnableHeaderConfig这个注解,
package com.example;import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableHeaderConfig {
}
上面加了注解@Import,@Import中指定我们要导入哪些配置类。而在MyImportSelector.class这个类中就制定了我们要导入哪些配置类。现在我们要指定导入哪些bean,直接在启动类上加上@EnableHeaderConfig这个注解即可。
package com.gjw;import ch.qos.logback.core.joran.event.SaxEvent;
import com.example.EnableHeaderConfig;
import com.example.HeaderConfig;
import com.example.MyImportSelector;
import com.example.TokenParser;
import org.dom4j.io.SAXReader;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;// @ComponentScan({"com.gjw","com.example"}) 方式一:采用@ComponentScan指定bean对象的扫描范围/*** 方式二:可以使用@Import注解* 可以用于:1.普通类* 2.配置类* 3.ImportSelector接口的实现类* 4.@EnableXXXX注解,封装@Import注解*/
//@Import({TokenParser.class}) // 普通类
//@Import({HeaderConfig.class}) // 配置类
//@Import(MyImportSelector.class) // MyImportSelector里面定义了要生成的bean对象
@EnableHeaderConfig // @EnableHeaderConfig继承封装了MyImportSelector
@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}
}
测试后HeaderParser这个bean对象存在。
第四种更方面优雅。
相关文章:
SpringBoot原理-03.自动配置-方案
一.自动配置原理 探究自动配置原理,就是探究spring是如何在运行时将要依赖JAR包提供的配置类和bean对象注入到IOC容器当中。我们当前准备一个maven项目itheima-utils,这里面定义了bean对象以及配置类,用来模拟第三方提供的依赖,首…...
Python 如何实现烟花效果的完整代码
文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons:JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram,自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 ? 5 IDEA必装的插件&…...
Winbox5怎样设置上网
要让连接到交换机的设备都能上网,需在MikroTik路由器(通过WinBox配置)上完成以下步骤。假设您的网络拓扑是:外网IP配置在路由器的WAN口,内网设备通过交换机连接到路由器的LAN口。 步骤 1:配置内网接口&…...
(KTransformers) RTX4090单卡运行 DeepSeek-R1 671B
安装环境为:ubuntu 22.04 x86_64 下载模型 编辑文件vim url.list 写入如下内容 https://modelscope.cn/models/unsloth/DeepSeek-R1-GGUF/resolve/master/DeepSeek-R1-Q4_K_M/DeepSeek-R1-Q4_K_M-00001-of-00009.gguf https://modelscope.cn/models/unsloth/Dee…...
【软考-架构】1.2、指令系统-存储系统-cache
GitHub地址:https://github.com/tyronczt/system_architect ✨资料&文章更新✨ 指令系统 计算机指令执行过程:取指令一一分析指令一一执行指令三个步骤,首先将程序计数器PC中的指令地址取出,送入地址总线,CPU依据…...
CI/CD与容器化技术核心知识点的QA
CI/CD与容器化技术核心知识点的Q&A 以下是CI/CD和容器化技术的经典必考面试题及详解,结合行业实践与理论核心整理而成: 一、CI/CD核心概念与流程 简述CI/CD的核心目标与实现价值 答案:通过自动化流水线实现快速、可靠的软件交付,减少人工干预,提升开发与运维协作效率…...
动态规划刷题
文章目录 动态规划三步问题题目解析代码 动态规划 1. 状态表示:dp[i],表示dp表中i下标位置的值 2. 状态转移方程:以i位置位置的状态,最近的一步来划分问题,比如可以将状态拆分成前状态来表示现状态,dp[i] …...
不谓侠--记录
音乐《不谓侠》 衣襟上 别好了晚霞 余晖送我牵匹老马 正路过 烟村里人家 恰似当年故里正飞花 醉过风 喝过茶 寻常巷口寻个酒家 在座皆算老友 碗底便是天涯 天涯远 无处不为家 蓬门自我也像广厦 论意气 不计多或寡 占三分便敢自称为侠 刀可捉 拳也耍 偶尔闲来…...
2025-03-01 学习记录--C/C++-C语言 整数类型对比
C语言 整数类型对比 类型位数范围(有符号)范围(无符号)格式化符号char8-128 到 1270 到 255%c 或 %hhdshort16-32,768 到 32,7670 到 65,535%hdint32-2,147,483,648 到 2,147,483,6470 到 4,294,967,295%dlong32 或 64-2,147,483…...
Python核心技术,Django学习基础入门教程(附环境安装包)
文章目录 前言1. 环境准备1.1Python安装1.2选择Python开发环境1.3 创建虚拟环境1.4 安装 Django 2. 创建 Django 项目3. Django项目结构介绍4. 启动开发服务器5. 创建 Django 应用6. 应用结构介绍7. 编写视图函数8. 配置 URL 映射9. 运行项目并访问视图10. 数据库配置与模型创建…...
MFC中CMutex类和CSingleLock类,配合使用疑惑
在使用CMutex过程中,看到别人使用了CSingleLock类,想着明明CMutex已经可以实现线程同步了,为什么还有使用CSingleLock类呢? 在MFC中,虽然CMutex类本身可以实现线程同步,但通常会与CSingleLock类一起使用&am…...
爬虫系列之【数据解析之正则】《二》
目录 前言 一、正则基本使用 1.1 导包 1.2 接口方法 1.3 换行匹配问题 二、实战案例 完整代码 前言 在爬虫工作中,我们主要会遇到两种类型的文本数据: JSON格式数据 HTML文档数据 对于JSON字符串数据,通常使用Python的字典操作进行键…...
HTML AI 编程助手
HTML AI 编程助手 引言 随着人工智能技术的飞速发展,编程领域也迎来了新的变革。HTML,作为网页制作的基础语言,与AI技术的结合,为开发者带来了前所未有的便利。本文将探讨HTML AI编程助手的功能、应用场景以及如何利用它提高编程…...
RFID工具柜DW-G104R|智能存储,便捷高效
一、行业背景 RFID智能工具柜(DW-G104R)RFID工具管理柜是一种结合RFID技术和智能柜设备的新型工具管理设施,通过自动化管理可以提高工具管理的效率和准确性。 在工业生产中,工具柜是工具存储和管理的重要设备。传统工具柜存在管…...
【前端面试】如何不通过正则:验证IP地址合法性
前言 在 Web 开发中,验证用户输入的 IP 地址是否合法是一个常见需求 面试中也会问到 通常,我们会使用正则表达式来完成这个任务,因为它简洁高效。然而,正则表达式对于初学者来说可能有些晦涩难懂。本文将介绍一种不使用正则表达…...
中间件专栏之Redis篇——Redis的三大持久化方式及其优劣势对比
Redis是内存数据库,它的数据一般存放在内存中,一旦断电或者宕机,存在内存中的数据就会丢失。当然,它也具备数据持久化的能力,本文就将介绍Redis的三种持久化方式及其优劣势对比。 一、RDB(Redis Database&…...
Linux软连接与时区日期
软连接 使用ln命令创建软连接。 在系统中创建软连接,可以将文件,文件夹连接到其他为止。 类似于Windows系统的快捷方式。 语法:ln -s 参数1 参数2 -s选项,创建软连接。 参数1,被链接的文件或文件夹。 参数2࿰…...
安全测试之五:SQL Server注入漏洞几个实例
示例 1:在 GET 请求中测试 SQL 注入 最简单且有时最有效的情况是针对登录页面进行测试。当登录页面请求用户输入用户名和密码时,攻击者可以尝试输入以下字符串 “ or 11”(不包含双引号): https://vulnerable.web.ap…...
2024 ChatGPT大模型技术场景与商业应用视频精讲合集(45课).zip
2024ChatGPT大模型技术场景与商业应用视频精讲合集,共十三章,45课。 01. 第一章 ChatGPT:通用人工智能的典范 1.1 ChatGPT概述 .mp4 1.2 通用能力 .mp4 1.3 通用人工智能风口 .mp4 02. 第二章 大模型:ChatGPT的核心支撑 2.1 底层…...
HTTP四次挥手是什么?
四次挥手,这是TCP协议用来关闭连接的过程。四次挥手是确保两个主机之间能够安全、可靠地关闭连接的重要机制。我会用简单易懂的方式来讲解,帮助你理解它的原理和过程。 1. 什么是四次挥手? 定义 四次挥手是TCP协议用来关闭连接的过程。它通…...
前端内存泄漏的几种情况及方案
前端内存泄漏是常见但容易被忽视的问题,可能导致页面卡顿、崩溃或性能下降。以下是几种典型场景及解决方案: 1. 未清理的全局变量 场景: 意外创建全局变量(未使用 var/let/const)。主动挂载到 window 的大对象未释放…...
人工智能之数学基础:线性代数中的特殊矩阵
本文重点 矩阵是数学中一个重要的工具,在各个领域都有广泛的应用。其中,一些特殊矩阵由于具有独特的性质,在特定的问题中发挥着关键作用。 单位矩阵 单位矩阵是一种特殊的方阵,在矩阵乘法中起到类似于数字 “1” 的作用。对于一个的单位矩阵,其主对角线元素全为 1,其余…...
单例模式---是 Spring 容器的核心特性之一
1.最近面试让手写一个单例;我一直知道单例;但是一直很困惑;工作中也没怎么用过;为什么面试总问;今天我才知道思考出来;单例是spring容器的核心特性;很多知识我只知道是什么;但是没有…...
代码随想录算法【Day59】
47. 参加科学大会 思路 使用Dijkstra 算法 计算从起点(节点 1)到终点(节点 n)的最短路径。用优先队列(小顶堆) 维护当前未访问的最短路径节点,每次选择距离最短的未访问节点进行更新ÿ…...
Linux篇——工具
在有了前面的基础知识后,我们现在基本能够使用Linux的相关基本操作了,但我们知道,没有工具我们是无法便捷地实现某些功能的,因此我们这篇内容来谈谈Linux中的工具。 一、软件包管理器yum 我们知道,我们要想获得一个软…...
leetcode第77题组合
原题出于leetcode第77题https://leetcode.cn/problems/combinations/ 1.树型结构 2.回溯三部曲 递归函数的参数和返回值 确定终止条件 单层递归逻辑 3.代码 二维数组result 一维数组path void backtracking(n,k,startindex){if(path.sizek){result.append(path);return ;}…...
通过fgets获取文件内容
#include <stdio.h> char *fgets(char *s, int size, FILE *stream); 使用fgets获取文件内容 #include <stdio.h> #include <stdlib.h>int main(void) {char str[100] {0};FILE *fp NULL;fp fopen("./test_file", "r");if (NULL …...
STaR(Self-Taught Reasoner)方法:让语言模型自学推理能力(代码实现)
STaR(Self-Taught Reasoner)方法:让语言模型自学推理能力 在大型语言模型(LLM)的推理能力优化中,STaR(Self-Taught Reasoner) 是一种引人注目的技术,属于“修改提议分布…...
[创业之路-329]:华为铁三角实施的步骤
一、通用过程 华为铁三角实施的步骤主要包括以下几个关键阶段: 1、明确角色与职责 确定铁三角成员:组建由客户经理(AR)、解决方案经理(SR)和交付经理(FR)组成的铁三角团队。制定岗…...
在 Ubuntu 下通过 Docker 部署 Caddy 和 PHP-FPM 服务器
引言 大家好,今天我们要聊的主题是如何在 Ubuntu 上通过 Docker 部署 Caddy 和 PHP-FPM 服务器。Caddy 是一个现代化的 web 服务器,支持 HTTPS,配置简单;而 PHP-FPM 是 PHP 的 FastCGI 进程管理器,能够高效处理 PHP 请…...
