如何理解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/658192.html

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

相关文章

Python散点图矩阵代码模版

本文分享Python seaborn实现散点图矩阵代码模版&#xff0c;节选自&#x1f449;嫌Matplotlib繁琐&#xff1f;试试Seaborn&#xff01; 散点图矩阵&#xff08;scatterplot matrix&#xff09;展示原始数据中所有变量两两之间关系&#xff0c;可以规避单一统计指标的偏差&…

【一步一步了解Java系列】:类与对象的联系

看到这句话的时候证明&#xff1a;此刻你我都在努力加油陌生人个人主页&#xff1a;Gu Gu Study专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹 喜欢的话可以点个赞谢谢了。 作者&#xff1a;小闭 对…

java 对接农行支付相关业务(二)

文章目录 农行掌银集成第三方APP1:掌银支付对接快e通的流程1.1 在农行网站上注册我们的app信息([网址](https://openbank.abchina.com/Portal/index/index.html))1.2:java整合农行的jar包依赖1.3:把相关配置信息整合到项目中1.4:前端获取授权码信息1.5:后端根据授权码信…

广东省旗袍文化促进会正式批复为世界酒中国菜活动的指导单位

广东省旗袍文化促进会正式批复荐酒师国际认证&#xff08;广州&#xff09;有限公司成为“世界酒中国菜”系列活动的指导单位 近日&#xff0c;广东省旗袍文化促进会正式批复荐酒师国际认证&#xff08;广州&#xff09;有限公司&#xff0c;成为备受瞩目的“世界酒中国菜”系…

怎样修改库包的文件名?

python中&#xff0c;安装crypto模块时&#xff0c;会遇到crypto文件夹都是小写字母的情况&#xff0c;引用时又是首字母大写&#xff0c;这个时候&#xff0c;需要把库包文件名首字母改为大写字母。windows中一般的文件名命名中字母的大小写是不进行区分的&#xff0c;但是在p…

linux中使用gdb调试c++的dump文件

1 查看系统是否开启dump生成 0表示没开启 ulimit -c 但是这个只是针对当前这个连接&#xff0c;如果想要永久修改可以修改配置文件&#xff1a;vim /etc/profile&#xff0c;然后添加上面的命令ulimit - c unlimited.然后执行source /etc/profile或者重启使刚刚的配置可以…

12.2 通道-阻塞与流程控制、通道型函数、退出通道

阻塞与流程控制 通常在并发程序中要尽力避免阻塞式操作&#xff0c;但有时又需要让代码暂时处于阻塞状态&#xff0c;以等待某种条件、信号或数据&#xff0c;然后再继续运行。 对于无缓冲通道&#xff0c;试图从无人写入的通道中读取&#xff0c;或者向无人读取的通道中写入…

蓝牙Mesh模块多跳大数据量高带宽传输数据方法

随着物联网技术的飞速发展&#xff0c;越来越多的设备需要实现互联互通。蓝牙Mesh网络作为一种低功耗、高覆盖、易于部署的无线通信技术&#xff0c;已经成为物联网领域中的关键技术之一。在蓝牙Mesh网络中&#xff0c;节点之间可以通过多个跳数进行通信&#xff0c;从而实现大…

广东商标协会批复为世界酒中国菜的指导单位

广东商标协会批复荐酒师公司成为“世界酒中国菜”活动指导单位 一、批复背景与意义 广东商标协会正式批复荐酒师国际认证&#xff08;广州&#xff09;有限公司&#xff0c;成为备受瞩目的“世界酒中国菜”系列活动的指导单位。该活动旨在共建“一带一路”倡议、助力“乡村振兴…

深度学习之CNN卷积神经网络

一.卷积神经网络 1. 导入资源包 import numpy as np import pandas as pd import matplotlib.pyplot as plt import sklearn import tensorflow as tf from tensorflow import keras注&#xff1a;from tensorflow import keras&#xff1a;从TensorFlow库中导入Keras模块&am…

第十三届蓝桥杯国赛大学B组填空题(c++)

A.2022 动态规划 AC; #include<iostream> #define int long long using namespace std; int dp[2050][15]; //dp[i][j]:把数字i分解为j个不同的数的方法数 signed main(){dp[0][0]1;for(int i1;i<2022;i){for(int j1;j<10;j){//一种是已经分成j个数,这时只需每一个…

Docker 快速更改容器的重启策略(Restart Policies)以及重启策略详解

目录 1. 使用 docker update 命令2. 在启动容器时指定重启策略3. 在 Docker Compose 文件中指定重启策略4. 总结 官方文档&#xff1a;Start containers automatically 1. 使用 docker update 命令 Docker 提供了 docker update 命令&#xff0c;可以在容器运行时更改其重启策…

Yann LeCun 和 Elon Musk 就 AI 监管激烈交锋

&#x1f989; AI新闻 &#x1f680; Yann LeCun 和 Elon Musk 就 AI 监管激烈交锋 摘要&#xff1a;昨天&#xff0c;Yann LeCun 和Elon Musk 在社交媒体就人工智能的安全性和监管问题展开激烈辩论。LeCun 认为目前对 AI 的担忧和监管为时过早&#xff0c;主张开放和共享。而…

OrangePi AIpro初体验:开启嵌入式开发之旅

概述 随着物联网和智能设备时代的到来&#xff0c;单板电脑因其独特的优势成为创新项目和教育实践的重要工具。在众多单板电脑中&#xff0c;香橙派以其出色的性能和亲民的价格&#xff0c;十分吸引博主这初涉嵌入式开发的新手。博主有幸被CSDN邀请对OrangePi AIpro进行测评。…

css中实现背景方格

background: rgba(241,241,241,0.1); background-image:linear-gradient(90deg, rgba(241,243,244,1) 10%, transparent 0),linear-gradient(rgba()241,243,244,1 10%, transparent 0); background-size: 10px 10px; 表现出来的样子就是这个样子

广东海上丝绸之路文化促进会正式批复荐世界酒中国菜的指导单位

广东海上丝绸之路文化促进会正式批复成为“世界酒中国菜”系列活动指导单位 近日&#xff0c;广东海上丝绸之路文化促进会近日正式批复荐酒师国际认证&#xff08;广州&#xff09;有限公司&#xff0c;成为备受瞩目的“世界酒中国菜”系列活动的指导单位。此举旨在通过双方的…

Android Compose 八:常用组件 Switch

Switch 切换按钮 val isChecked remember { mutableStateOf(true) }Switch(checked isChecked.value,onCheckedChange {Log.i("text_compose","onCheckedChange>>"it)isChecked.value it})效果 默认颜色 应该对应 主题色 1.1 thumbContent 按钮…

盘点好用的国产传输软件,看看哪个适合你

流动让数据释放价值&#xff0c;无论什么企业&#xff0c;什么行业&#xff0c;业务的正常开展均是以数据和文件的传输为基础&#xff0c;因此&#xff0c;对企业来说&#xff0c;文件传输工具是最基础但也是最举重若轻的。在琳琅满目的多种国产传输软件中&#xff0c;哪个是最…

Java基础:基本语法(一)

Java基础&#xff1a;基本语法&#xff08;一&#xff09; 文章目录 Java基础&#xff1a;基本语法&#xff08;一&#xff09;1. 前言2. 开发环境搭建2.1 Java开发工具包下载2.2 环境变量配置2.3 Java程序的运行过程 3. 数据类型3.1 基本数据类型3.2 引用数据类型 4. 常量与变…

晓语台:基于大语言模型和深度学习技术的智能创作平台,高效、个性化地创作高质量内容。

晓语台 AI&#xff1a; 晓语台是由北京字里心间科技有限公司推出的一款智能AI写作工具。它基于百度的大语言模型和混合大模型以及AIGC技术研发而成&#xff0c;内置了多种风格和主题的AI创作模板&#xff0c;覆盖了20余类行业与职业&#xff0c;近30个海内外社交平台&#xff…