Spring Boot自动配置原理和应用

我们知道,基于Spring Boot,我们只需要在类路径中引入一组第三方框架的starter组件,就能在Spring容器中使用这些框架所提供的各项功能。这在当下的开发过程中已经习以为常,但在Spring Boot还没有诞生之前却是不可想象的。如果我们使用传统的Spring框架,那就需要添加各种繁杂的配置信息才能启动容器。那么,Spring Boot是通过那种机制来做到这一点的呢?这就是本文我们要讨论的内容,即Spring Boot的自动配置机制。

可以说,Spring Boot的自动配置机制应用也非常广泛,在目前主流的开源框架中,都提供了各自的starter组件。例如,Mybatis的starter组件为mybatis-spring-boot-starter。而从扩展性上讲,这也是Spring Boot为开发人员提供了一整套扩展机制,我们可以基于这套扩展机制实现自定义的starter组件。

Spring Boot自动配置机制原理

Spring Boot的自动配置功能强大,但也有一定的复杂度,让我们先来深入理解其背后的实现原理。

@EnableAutoConfiguration注解

我们通过查看@SpringBootApplication注解的定义,发现该注解实际上是一个复合注解,由@SpringBootConfiguration、@ComponentScan和@EnableAutoConfiguration所组成。


我们知道@ComponentScan是传统Spring框架中就内置的注解,而@SpringBootConfiguration注解也很简单,实际上只是对Spring框架中另一个常用组件@Configuration的一种包装,本身没有定义任何内容。所以,我们接下来重点剖析@EnableAutoConfiguration注解。

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage

@Import(AutoConfigurationImportSelector.class)

public @interface EnableAutoConfiguration {

String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

Class<?>[] exclude() default {};

String[] excludeName() default {};

}

可以看到,这里出现了一个新的注解,即@AutoConfigurationPackage。从命名上讲, @AutoConfigurationPackage注解的作用就是自动对某一个代码包进行配置。

另一方面,我们还看到通过@Import注解引入了一个AutoConfigurationImportSelector对。从命名上,我们也不难理解该类的作用是完成对导入的配置信息的自动选择。该类的核心方法getCandidateConfigurations实现了这一目标

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

return configurations;

}

这里引出了在Spring Boot中真正负责加载配置信息的SpringFactoriesLoader类。

这些类之间的交互关系如下图所示。


显然,想要完成配置信息的自动选择,我们首先需要执行配置文件的加载操作,这部分功能是由SpringFactoriesLoader来完成的。SpringFactoriesLoader也是Spring Boot自动配置得以实现的关键组件,我们来一起看一下。

SpringFactoriesLoader

SpringFactoriesLoader类似JDK中的SPI机制所使用的ServiceLoader类,区别只是在配置文件的存放位置和配置项对应的键值定义。在SpringFactoriesLoader中,我们需要通过META-INF/spring.factories文件夹获取服务定义文件,并通过EnableAutoConfiguration这个健值来获取具体的配置信息。下图展示了SpringFactoriesLoader和ServiceLoader之间的区别。


SpringFactoriesLoader基于上图中指定的配置文件名和键值获取对应的配置信息,然后基于这些配置信息来实例化配置类,Spring Boot通过反射机制实现了这一目标。SpringFactoriesLoader类中的loadSpringFactories方法展示了这一过程。

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {

//从缓存中获取配置内容,如果存在则直接返回

try {

//基于ClassLoader从META-INF/spring.factories获取配置文件资源地址URL

while (urls.hasMoreElements()) {

//获取配置文件资源

//加载配置项

for (Map.Entry<?, ?> entry : properties.entrySet()) {

//组装配置项Key-Value

}

}

//把配置信息放入缓存

//返回结果

}

}

我们在spring-boot-autoconfigure工程中所使用的spring.factories配置文件中知道了如下所示配置项。

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\

org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\

org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\

org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\

可以看到在org.springframework.boot.autoconfigure.EnableAutoConfiguration配置项中定义了各种以-AutoConfiguration结尾的配置类。通过SpringFactoriesLoader,Spring Boot就能做到在服务启动的过程中把它们记载到容器中并实现自动化配置。

Mybatis Spring Boot Starter

介绍完Spring Boot中应用程序的自动配置机制之后,我们来做一些实践,通过剖析Mybatis Spring Boot Starter的启动过程来加深对所介绍内容的理解。

在mybatis-spring-boot-starter中存在几个代码工程,我们重点关注mybatis-spring-boot-autoconfigure工程。而在这个代码工程中,最重要的显然就是MybatisAutoConfiguration类。对于Spring Boot中的AutoConfiguration类,我们首先需要重点关注的是类定义上的注解,如下所示。

@org.springframework.context.annotation.Configuration

@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })

@ConditionalOnSingleCandidate(DataSource.class)

@EnableConfigurationProperties(MybatisProperties.class)

@AutoConfigureAfter(DataSourceAutoConfiguration.class)

public class MybatisAutoConfiguration implements InitializingBean {

我们看到这里用到了新的@ConditionalOnClass和@ ConditionalOnSingleCandidate注解,它们就是Spring Boot中的条件注解。在介绍MybatisAutoConfiguration之前,有必要对这些注解做一定展开。

@ConditionalOn系列条件注解

我们在前面的介绍中已经了解到以-AutoConfiguration结尾的自动配置类数量会很多,在一个应用程序的开发过程中,我们通常不会全部使用到。这时候就需要引入一种机制来对这些自动配置类进行过滤。为此,Spring Boot提供了一组@ConditionalOn系列条件注解。通这些注解,我们就可以基于特定的条件来选择性的加载某些配置类。在Spring Boot中常见的条件注解可以参考下图。


在前面介绍的MybatisAutoConfiguration类上,我们发现了@ConditionalOnClass和@ConditionalOnSingleCandidate这两个条件注解。基于这两个条件注解,我们可以明确MybatisAutoConfiguration能够实例化的前提有两个,一个是类路径中存在SqlSessionFactory和SqlSessionFactoryBean,另一个是容器中只存在一个DataSource实例。两者缺一不可,这是一种常用的自动配置控制技巧。

然后,我们在MybatisAutoConfiguration类上看到了一个@EnableConfigurationProperties注解。通过这个注解,所有添加了@ConfigurationProperties 注解的配置类就会自动生效。这里的@EnableConfigurationProperties注解中指定的是MybatisProperties类,该类定义了Mybatis运行时所需要的各种配置信息,而我们在MybatisProperties类上确实也发现了@ConfigurationProperties注解,并指定了prefix为"mybatis"。

@ConfigurationProperties(

     prefix = "mybatis"

)

public class MybatisProperties {

...

}

最后,在MybatisAutoConfiguration类上还存在一个@AutoConfigureAfter注解,这个注解可以根据字面意思进行理解,即在完成某一个类的自动配置之后再执行当前类的自动配置,这个需要提前装配的类指的就是DataSourceAutoConfiguration。

MybatisAutoConfiguration

理解上@ConditionalOnXXX、@EnableConfigurationProperties和@AutoConfigureAfter等一系列注解之后,我们回过头来再看MybatisAutoConfiguration类的代码结构就显得比较简单明了。MybatisAutoConfiguration类中核心方法之一就是如下所示的sqlSessionFactory方法。

@Bean

@ConditionalOnMissingBean

public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {

    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();

    factory.setDataSource(dataSource);

    factory.setVfs(SpringBootVFS.class);

    if (StringUtils.hasText(this.properties.getConfigLocation())) {

      factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));

    }

    applyConfiguration(factory);

    

    //省略一系列配置项设置方法    

    return factory.getObject();

}

显然,这里基于前面介绍的SqlSessionFactoryBean构建了SqlSessionFactory实例。注意到在该方法上同样添加了一个@ConditionalOnMissingBean注解,标明只有在当前上下文中不存SqlSessionFactoryBean对象时才会执行上述方法。

同样添加了@ConditionalOnMissingBean注解的还有如下所示的sqlSessionTemplate方法。

@Bean

@ConditionalOnMissingBean

public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {

    ExecutorType executorType = this.properties.getExecutorType();

    if (executorType != null) {

      return new SqlSessionTemplate(sqlSessionFactory, executorType);

    } else {

      return new SqlSessionTemplate(sqlSessionFactory);

    }

}

该方法用于构建一个SqlSessionTemplate对象实例。在Mybatis中,SqlSessionTemplate实现了SqlSession接口,相当于是全局唯一的SqlSession实例。

接下来,我们需要在META-INF/spring.factories文件中明确所指定的自动配置类。根据Spring Boot自动配置机制的原理,对于mybatis-spring-boot-autoconfigure工程而言,这个配置项内容应该如下所示。

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

至此,整个Mybatis Spring Boot Starter的介绍就告一段落。作为总结,我们可以把创建一个Spring Boot Starter的过程抽象三个步骤。


在日常开发过程中,我们就可以基于这三大步骤来实现一个自定义的Spring Boot Starter。

总结

本文内容详细阐述了Spring Boot自动配置机制的实现原理,从源码角度分析了为什么Spring Boot能够做到自动配置,并结合Mybatis框架分析了它在开源框架中的具体应用。同时,我们在本讲结尾部分还总结了开发一个Spring Boot Starter的三大步骤,开发一个Spring Boot Starter也是常见的需求,我们在开发过程中可以基于本讲的内容加深对其实现原理的理解。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Text2SQL 论文】QDecomp:探索 CoT-style 的 prompt 来解决 Text2SQL

论文&#xff1a;Exploring Chain of Thought Style Prompting for Text-to-SQL ⭐⭐⭐⭐ EMNLP 2023, arXiv:2305.14215 一、论文速读 本文通过对 LLM 使用 CoT-style 的 prompting 方法来解决 Text2SQL 问题&#xff0c;试图回答下面两个问题&#xff1a; 哪种 prompting s…

英伟达GPU架构加速狂飙

NVIDIA首席执行官黄仁勋在台湾大学体育馆发表主题演讲&#xff0c;展示了新一代Rubin架构&#xff0c;这是NVIDIA加速推出新架构的最新成果。 在讨论NVIDIA下一代架构时&#xff0c;黄仁勋提到了Blackwell Ultra GPU&#xff0c;并表示它可能会继续升级。然后他透露&#xff0c…

Zoom | saas企业分销裂变的典范

提到视频通讯&#xff0c;相信大家不会陌生&#xff0c;国外有Skype、Google meeting、Facetime&#xff0c;国内有腾讯会议、钉钉&#xff0c;为什么在如此众多竞争对手的情况下&#xff0c;Zoom能够一马当先&#xff0c;成为行业先锋&#xff1f; 一、公司简介 Zoom是集视频…

【电路笔记】-Sallen-Key滤波器

Sallen-Key滤波器 Sallen-Key 滤波器拓扑用作实现高阶有源滤波器的构建块。 1、概述 Sallen-Key 滤波器设计是一种二阶有源滤波器拓扑,我们可以将其用作实现高阶滤波器电路的基本构建块,例如低通 (LPF)、高通 (HPF) 和带通 ( BPF)滤波器电路。 正如我们在本滤波器部分中…

反激电源的类型与特点

主要分为 1 固定频率&#xff08;CCMDCM&#xff09; 2 可变频率控制&#xff08;CRM电流临界模式&#xff09; 这三种模式是很好辨别的&#xff0c;首先我们看左边的连续模式&#xff0c;Vds能看到他有一些尖峰毛刺&#xff0c;这是场效应管关闭的时候&#xff0c;LRC谐振导…

揭秘FL Studio21.2.8中文版一键解锁音乐创作新境界!

在音乐制作的广阔天地里&#xff0c;随着技术的不断进步和数字音频工作站&#xff08;DAW&#xff09;软件的普及&#xff0c;越来越多的音乐爱好者和专业制作人开始涉足音乐创作的奇妙旅程。其中&#xff0c;FL Studio以其强大的功能、直观的操作界面和丰富的音色资源&#xf…

用户管理的小demo--登录校检

目录 在user里面 装session 1、 LoginServlet.java 2、LoginFilter.java 3、配置路径 结果&#xff1a; 在user里面 装session 1、 LoginServlet.java package com.by.servlet;import com.by.pojo.User; import com.by.service.UserService; import com.by.service.impl…

云原生环境下GPU算力调度发展分析

云原生环境下GPU算力调度深度分析 概述&#xff1a; 云原生时代&#xff0c;GPU算力调度与管理备受瞩目&#xff0c;成为企业和云服务提供商关注的焦点&#xff0c;助力AI、深度学习、高性能计算等领域&#xff0c;满足对GPU资源的迫切需求。 容器化与编排&#xff1a; Kube…

LLM的基础模型4:初识Embeddings

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则提…

2024.5.30

思维导图 代码 #include <iostream>using namespace std; class Rect { private:int width;int height; public:void init(int w,int h){width w;height h;}void set_w(int w){width w;}void set_h(int h){height h;}void show(){int zhou (width height) * 2;int…

vue-router 源码分析——2. router-link 组件是如何实现导航的

这是对vue-router 3 版本的源码分析。 本次分析会按以下方法进行&#xff1a; 按官网的使用文档顺序&#xff0c;围绕着某一功能点进行分析。这样不仅能学习优秀的项目源码&#xff0c;更能加深对项目的某个功能是如何实现的理解。这个对自己的技能提升&#xff0c;甚至面试时…

使用raise语句抛出异常

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 如果某个函数或方法可能会产生异常&#xff0c;但不想在当前函数或方法中处理这个异常&#xff0c;则可以使用raise语句在函数或方法中抛出异常。rai…

车联网安全之GPS欺骗

随着车辆GPS技术的广泛应用&#xff0c;其在导航、交通监控等方面的关键性日益凸显&#xff0c;与之相关的安全性问题也备受关注。GPS欺骗便是其中一种重要的威胁手段。 本文旨在使用模拟GPS欺骗设备&#xff0c;模拟不同的GPS攻击以评估其对车辆定位系统的影响。通过这个实验…

「不只是框架:Django REST framework的超能力大揭秘」

想要让你的API服务像五星级餐厅一样令人难忘吗&#xff1f;今天阿佑将为你揭晓&#xff01;从基础的RESTful原则到Django REST framework的高级特性&#xff0c;我们一步步带你走进API开发的后厨&#xff0c;展示如何准备食材&#xff08;数据模型&#xff09;、调制酱料&#…

记录一次云服务器无法连接的排查过程

运行环境&#xff1a;阿里云服务器 故障外显原因&#xff1a;登录失败,操作系统禁用了密码登录方式 控制台监控数据显示云盘读写BPS拉满了 因为之前问过线上售后&#xff0c;让安装了atop监控&#xff0c;&#xff0c;所以先打开atop日志&#xff1a; atop -r /var/log/atop…

try…except…else语句

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在Python中&#xff0c;还有另一种异常处理结构&#xff0c;它是try…except…else语句&#xff0c;也就是在原来try…except语句的基础上再添加一个…

关于博图17安装体验过程—博图17安装失败原因(STEP7 许可证找不到)

目录 一、序言 二、正片 一、序言 该失败原因是在我使用Win11专业版安装博图17时出现的问题&#xff0c;也仅代表我的体验过程&#xff01;以下我将安装过程和解决问题的过程描述一下&#xff0c;希望可以帮助和我一样自己安装博图时能够解决出现的问题。 二、正片 如果阁下…

DRIVEN|15分的CNN+LightGBM怎么做特征分类,适用于转录组

说在前面 今天分享一篇做深度学习模型的文章&#xff0c;这是一篇软硬结合的研究&#xff0c;排除转换实体产品&#xff0c;我们做生信基础研究的可以学习模仿这个算法&#xff0c;适用且不局限于临床资料&#xff0c;转录组数据&#xff0c;GWAS数据。 今天给大家分享的一篇文…

构造+割点,F2. Spanning Tree with One Fixed Degree

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 Problem - 1133F2 - Codeforces 二、解题报告 1、思路分析 考虑以根节点为割点&#xff0c;会有若干个连通块 连通块的数目为根节点至少要连出去的边&#xff0c;不妨记为mi 如果mi > D&#xff0c;那…