【原理篇】三、SpringBoot自动配置原理

news2024/11/24 10:31:06

文章目录

  • 0、背景demo
  • 1、自动配置思路
  • 2、META-INF/spring.factories
  • 3、Redis自动配置
  • 4、自定义一个自动配置
  • 5、排除SpringBoot内置自动配置类的加载
  • 6、补充点:ApplicationContextAware接口

0、背景demo

用一个循序渐进的示例来体验属性配置,方便后面理解自动配置,先准备几个demo类:

@Data
public class Cat{

	private String name;
	
	private Integer age;
}
@Data
public class Mouse{

	private String name;
	
	private Integer age;
}
//猫和老鼠卡通类
@Component
public class CartoonCatAndMouse{

	private Cat cat;

	private Mouse mouse;

	//提供个构造方法给两个属性赋值,不然默认null,下面会空指针
	public CartoonCatAndMouse(){
		cat = new Cat();
		cat.setName("tom");
		cat.setAge(3);
		mouse= new Mouse();
		mouse.setName("jerry");
		mouse.setAge(3);
	}

	public void play(){
		System.out.println(cat.getAge()+"岁的"+cat.getName()+"与"+mouse.getAge()+"岁的"+mouse.getName()+"打起来了");
	}
}
//启动类中调用下play方法
@SpringBootApplication
public class App{

	public static void main(String[] args){
		
		ConfigurableApplicationContext ctx = SringApplication.run(app.class);
		
		CartoonCatAndMouse bean = ctx.getBean(CartoonCatAndMouse.class);
		
		bean.play();
	}
}

在这里插入图片描述

此时,配置都硬编码了,显然不合理。

优化第一步:引入yaml配置并@ConfigurationProperties读取

cartoon:
  cat:
    name: tom
    age: 3
  mouse:
    name: jerry
    age: 4
@Component
@ConfigurationProperties(prefix = "cartoon")
//加个set,不然cat属性和mouse属性为null
@Data  
public class CartoonCatAndMouse{

	private Cat cat;

	private Mouse mouse;

	public void play(){
		System.out.println(cat.getAge()+"岁的"+cat.getName()+"与"+mouse.getAge()+"岁的"+mouse.getName()+"打起来了");
	}
}

此时,如果yaml配置中没有相关配置,则对应的对象为null,进而空指针。也就是说,一加@ConfigurationProperties(prefix = “cartoon”),我的类和yaml配置绑死了,没配置,类都受影响。

优化第二步:引入独立配置类CartoonProperties

@ConfigurationProperties(prefix = "cartoon")
@Data
//旧知识点,读取yaml的类的对象必须受Spring容器管控,否则,即使拿到yaml值也无法set给你
@Component
public class CartoonProperties {
	private Cat cat;
	private Mouse mouse;
}

@Component
@Data  
public class CartoonCatAndMouse{

	private Cat cat;

	private Mouse mouse;
	
	//构造器注入了,用@Autowired也行
	private CartoonProperties cartoonProperties;

	public void play(CartoonProperties cartoonProperties){
		
		this.cartoonProperties = cartoonProperties;
		cat = new Cat();
		cat.setName(cartoonProperties.getCat()!=null && StringUtils.hasText(cartoonProperties.getCat().getName())
					?cartoonProperties.getCat().getName():"tom");  //有则用,无则用默认值
		//Mouse对象同样写法,略
		System.out.println(cat.getAge()+"岁的"+cat.getName()+"与"+mouse.getAge()+"岁的"+mouse.getName()+"打起来了");
	}
}

此时,有个缺点,CartoonProperties类不管用不用,都被强制加载成一个Bean了,但去掉@Component,只留@ConfigurationProperties语法错误 ⇒ 用@EnableConfigurationProperties

优化第三步:@EnableConfigurationProperties,改掉强制加载Bean

//@Component 不再需要定义为Bean
@ConfigurationProperties(prefix = "cartoon")
@Data
public class CartoonProperties {
	private Cat cat;
	private Mouse mouse;
}

@ConfigurationProperties和@EnableConfigurationProperties,前者是做属性绑定的,后者是开启属性绑定,并设定对应的目标是谁

@Component  //这个Component也可以去掉,用的时候@Import(CartoonCatAndMouse.class)
@Data  
//即当我加载CartoonCatAndMouse时,就用CartoonProperties.class,并把CartoonProperties类加载成Bean
@EnableConfigurationPropertiesCartoonProperties.class)   
public class CartoonCatAndMouse{

	private Cat cat;

	private Mouse mouse;

	//重复代码,略....

这套模式的亮点有以下几个:

  • 合理的加载配置文件,即你配置了就用你的,没配就用默认值来工作
  • 对于属性类xxxProperties不用强制配置成Bean,使用@EnableConfigurationProperties
  • 对于业务功能的Bean,通常使用@Import将一个类加载成Bean,来解耦强制加载Bean,以降低Spring容器管理Bean的工作量以及强度

1、自动配置思路

  • 收集Spring开发者的编程习惯,得到常用技术集列表 ⇒ 技术集A
  • 收集每个技术的常用参数值,得到常用配置值列表 ⇒ 设置集B
  • 初始化你项目的SpringBoot基础环境,包括加载用户自定义的Bean以及用户导入的其他坐标,得到初始化环境
  • 把技术集A中具有使用条件的技术设置为按条件加载,与初始化环境对比,如有Redis核心类时,就触发加载Redis技术集的资源
  • 约定大于配置,设置集B里的参数值做为默认配置加载
  • 对于要修改的配置,开发者自行覆盖

总之就是,SpringBoot官方整理了常用的技术以及对应的配置值,可根据你项目的环境来自动加载相关的Bean,并给你默认配置,减少开发者的工作量。

2、META-INF/spring.factories

从启动类的@SpringBootApplication注解开始看:

在这里插入图片描述
关键点:

  • @Import(AutoConfigurationPackages.Registrar.class) ,debug可发现,这里是设置当前配置所在的包为扫描包,后续要针对当前包进行扫描
  • @Import(AutoConfigurationImportSelector.class)

继续往下看AutoConfigurationImportSelector,它实现了很多接口,可分三类:

  • DeferredImportSelector文末补充点一节
  • Ordered:有关Bean的创建顺序

重写的DeferredImportSelector接口中的process方法中除去断言代码,往下debug看getAutoConfigurationEntry方法:

在这里插入图片描述

调用了获取候选配置的方法getCandidateConfigurations:

在这里插入图片描述

跳过断言代码,看到核心肯定在loadFactoryNames方法:

在这里插入图片描述
继续debug方法loadFactoryNames,除去判空,关键的在loadSpringFactories方法:

在这里插入图片描述

可以看到loadSpringFactories方法在读META-INF/spring.factories里的资源,这里就是核心了。

在这里插入图片描述

3、Redis自动配置

查看SpringBootAutoConfiguration下的spring.factories文件:

在这里插入图片描述

以Redis的自动装配为例来看:spring.factories文件钟找到了RedisAutoConfiguration类,即Redis的自动配置类:

在这里插入图片描述

对比前面刚开始的背景案例,这个Redis的自动装配就很明晰了:

  • @ConditionOnClass是Redis相关Bean加载的条件,引入Redis起步依赖后,里面包含这里的RedisOperations.class类,也就满足了加载条件
  • @EnableConfigurationProperties后面是属性配置类
  • @Import导入两个Redis底层的Bean
  • 定义两个Redis客户端操作的Template的Bean,并前提是用户没有自定义这个Bean

这就是前面提到的,SpringBoot加了无数技术的自动配置类,用对应的条件来检测你当前Spring项目中要不要加对应的技术的Bean等资源。

4、自定义一个自动配置

对比上面的Redis自动配置类和开篇的demo,前面的CartoonCatAndMouse类就是RedisAutoConfiguration,CartoonProperties就是RedisProperties,那就模仿官方写法,把CartoonCatAndMouse改成一个真正的自动配置类。新建META-INF/spring.factories,内容:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.plat.bean.CartoonCatAndMouse

此时,CartooCatAndMouse就完成了自动配置,修一下,加上加载条件:

@Data 
@ConditionalOnClass(name = "com.plat.core.MyCore.class")
@EnableConfigurationPropertiesCartoonProperties.class)   
public class CartoonCatAndMouse{

	private Cat cat;

	private Mouse mouse;

	//重复代码,略....

此时,项目启动,有MyCore.class类被加载时,触发自动装配,完成相关Bean的加载。最后,如果直接把一个类配置到spring.factories文件中,能从IoC容器中get到这个Bean吗? ==> 可以,但属性都为null

5、排除SpringBoot内置自动配置类的加载

截至SpringBoot2.6版本,spring.factories中已有130多种技术对应的自动配置类,没必要启动时去全部判断一次,可以直接排除掉一些你肯定不用的自动配置类。

  • 方法一:配置文件
spring:
  autoconfigure:
    exclude: 
      - org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
      - org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration
  • 方法二:注解
@SpringBootApplication(excludeName = "",exclude = {})

//exclude属性其实是@EnableAutoConfiguration注解的,但它被@SpringBootApplication包含,属性也被拿了过来
  • 方式三:排除掉依赖,直接通过干涉激活条件@Conditional实现,如去除tomcat自动配置(条件激活),添加jetty自动配置(条件激活)

在这里插入图片描述

6、补充点:ApplicationContextAware接口

获取ApplicationContext对象,可以通过实现ApplicationContextAware接口:

@Component
public class MyIocUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext){
        this.applicationContext = applicationContext;    //给当前工具类的applicationContext属性赋值
    }
 
    public static ApplicationContext getApplicationContext(){
        return applicationContext;
    }
}

此时,在你需要使用上下文对象的地方直接:

MyIocUtils.getApplicationContext()

即可拿到上下文对象。当然你不封装成工具类也行,直接在你需要用上下文对象的类里写:

public class YourClass{

	private ApplicationContext applicationContext;
	
	@Override
    public void setApplicationContext(ApplicationContext applicationContext){
        this.applicationContext = applicationContext;    //给当前类的applicationContext属性赋值
    }

	public void doSome(){
		//使用上下文对象
		applicationContext.getBean........
	}
}

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

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

相关文章

62、使用python进行rk3588开发板进行推流亚马逊云服务上,进行实时播放

基本思想:之前写了一套c++的推理和视频编解码,使用rk3588的mpp硬件进行编码和解码,然后使用RTSPServer进行推流,总是有问题,虽然可以使用ffplay和vlc进行拉取和播放,但是就是无法使用gstreamer推流到亚马逊云服务上,因为项目需求的紧急,所以先用python把流程跑同,后续…

【机器学习】Kmeans聚类算法

一、聚类简介 Clustering (聚类)是常见的unsupervised learning (无监督学习)方法,简单地说就是把相似的数据样本分到一组(簇),聚类的过程,我们并不清楚某一类是什么(通常无标签信息)&#xff0…

Stable Diffusion被爆包含性别、种族歧视!比AI更可怕的是人类的偏见......

夕小瑶科技说 原创 作者 | 付奶茶、王二狗最近,华盛顿邮报的一篇报道引起了“奶茶”我的关注! 报道中提到AI图像生成器已经开始暴露出它们学到的偏见。比如将非洲人刻板地视为原始,将领导者默认为男性,将囚犯一般视为黑人。 为了…

内衣专用洗衣机怎么样?家用小洗衣机推荐

最近这两年在洗衣机中火出圈的内衣洗衣机,它不仅可以清洁我们较难清洗的衣物,自带除菌功能,可以让衣物上的细菌,还能在清洗的过程中呵护我们衣物的面料,虽然说它是内衣洗衣机,它的功能不止可以清洗内衣&…

基于YOLOv8与DeepSORT实现多目标跟踪——算法与源码解析

一、概述 "目标跟踪 (Object Tracking)"是机器视觉领域中的一个重要研究领域。根据跟踪的目标数量,可以将其分为两大类:单目标跟踪 (Single Object Tracking,简称 SOT) 和多目标跟踪 (Multi Object Tracking,简称 MOT)…

『 MySQL数据库 』数据库基础之库的基本操作

文章目录 库的操作创建数据库字符集与校验集那么该如何查看当前数据库默认的字符集与校验规则?查看数据库所支持的字符集与校验集不同字符集(校验集)之间的区别 基本操作查看数据库显式数据库创建语句数据库的修改数据库的删除数据库的备份检查连接 库的操作 创建数据库 CRE…

记一次 Android 周期性句柄泄漏的排查

滴滴国际化外卖 Android 商户端正常迭代版本过程中,新版本发布并且线上稳定一段时间后,突然触发线上 Crash 报警。 第一次排查发现是在依赖的底层平台 so 库中崩溃,经过沟通了解到其之前也存在过崩溃问题,所以升级相关底层 so 版本…

家居品牌怎么做小红书投放,寻找家居达人的方式有哪些?

在当今社交媒体的时代,找到优秀的家居博主并不困难。但是,在找家居行业博主的时候,了解家居行业特性就很重要,今天来为大家分享一下家居品牌怎么做小红书投放,寻找家居达人的方式有哪些? 一、家居行业特性 …

共享盘的文件删除后能找回吗

在当今高度信息化的时代,数据和文件的重要性日益凸显。然而,由于各种原因,我们有时会不小心删除了一些重要的文件,这时候就会面临数据恢复的问题。那么,对于共享盘的文件,删除后是否还能找回呢?…

conda环境下version libcublasLt.so.11 not defined问题解决

1 问题描述 运行模型训练&#xff0c;错误信息如下&#xff1a; Traceback (most recent call last):File "/opt/Bert-VITS2/./text/chinese_bert.py", line 3, in <module>import torchFile "/root/anaconda3/envs/vits/lib/python3.9/site-packages/t…

如何从存档服务器上完全删除PDM用户

当创建新用户时使用“PDM 登录”类型&#xff08;如下图&#xff09;&#xff0c;PDM用户名和密码会存储于存档服务器的注册表中。 存档服务器的注册表位置如下&#xff1a; HKEY_LOCAL_MACHINE\SOFTWARE\SolidWorks\Applications\PDMWorks Enterprise\ArchiveServer\ConisioU…

【Vue】组件封装小技巧 — 利用$attrs和v-bind接收传递未定义的属性

使用介绍 在Vue.js中&#xff0c;$attrs 和v-bind可以用于组件的二次封装&#xff0c;以在封装的组件中传递父组件的属性和事件。这对于创建高度可定制的通用组件非常有用。 下面是一些示例代码&#xff1a; 假设你有一个名为MyButton的自定义按钮组件&#xff0c;它接受一些…

Apipost发起请求,能正确返回,日志却打印java.io.EOFException: null 的原因

http响应头首部Content-Length - 程序员大本营 http响应头首部Content-Length HTTP Content-Length深入实践-CSDN博客 用了这么久HTTP, 你是否了解Content-Length?-CSDN博客 具体分析可看上面参考文章。 解决办法&#xff1a;可在请求头加上Content-Length&#xff0c;准确…

linux服务器添置一块新硬盘操作

之前有一台ubuntu服务器&#xff0c;考虑未来存储容量可能不够&#xff0c;添加了一块新的硬盘&#xff0c;这是本次添置硬盘过程。 首次接上硬盘&#xff0c;提示&#xff1a; 没有找到新接入设备&#xff0c;查看接线&#xff0c;主板有个硬盘接线端子坏了&#xff0c;更换一…

机器视觉opencv答题卡识别系统 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 答题卡识别系统 - opencv python 图像识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分…

新翔绩效考核系统

介绍&#xff1a; 新翔绩效考核系统&#xff0c;是新翔软件有限公司整合众多企事业单位绩效考核需求&#xff0c;而开发的网络版绩效管理软件。软件分前台手机端评分页面和后台电脑端管理页面&#xff0c;可实现360度绩效考核、KPI考核等模式考核&#xff0c;评分方式多样、设…

计算机毕设 基于情感分析的网络舆情热点分析系统

文章目录 0 前言1 课题背景2 数据处理3 文本情感分析3.1 情感分析-词库搭建3.2 文本情感分析实现3.3 建立情感倾向性分析模型 4 数据可视化工具4.1 django框架介绍4.2 ECharts 5 Django使用echarts进行可视化展示5.1 修改setting.py连接mysql数据库5.2 导入数据5.3 使用echarts…

【网络面试必问(6)】IP协议对网络包的转发

接上一篇&#xff1a;【网络面试必问&#xff08;5&#xff09;】网络收发数据及断开服务器&#xff08;四次挥手&#xff09; 在之前的博客中&#xff0c;我们提到过&#xff0c;网络传输的报文是有真实的数据包和一些头部组成的&#xff0c;目前我们了解的头部就有TCP头、IP头…

VueUse、View Transitions API实现暗黑模式主题动画切换效果

VueUse、View Transitions API实现暗黑模式主题动画切换效果 前言View Transitions API兼容版本 VueUse 正题效果安装代码 作者GitHub&#xff1a;https://github.com/gitboyzcf 有兴趣可关注&#xff01;&#xff01; 前言 View Transitions API View Transitions API 是原生…

华东理工大学漏洞报送证书

获取来源&#xff1a;edusrc&#xff08;教育漏洞报告平台&#xff09; url&#xff1a;主页 | 教育漏洞报告平台 兑换价格&#xff1a;20金币 获取条件&#xff1a;提交华东理工大学任意中危或以上级别漏洞 证书规格&#xff1a;附送图二实物及封皮