Spring Boot究竟是如何进行自动配置的!

我们都知道 SpringBoot 是要比原始的 SpringMVC 这些好用的,毕竟如果经历过最早的 SSM 模式的开发的话,一定对那些大批量的繁琐的配置文件印象颇深,因为之前使用 SSM 框架来进行开发的时候,那配置文件多的让人心态都容易崩溃,所以就有了这个 SpringBoot 来简化这些配置项,于是面试官就开始了对 SpringBoot 的各种面试题的问法,而比较经典的,就是 SpringBoot 是如何实现自动配置的。

配置属性

在通常需要我们在property中配置信息时,通常使用@ConfigurationProperties(pefix=“前缀”)注解的方式从配置文件中获取配置,如下:

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.boot.context.properties.ConfigurationProperties;@RestController
@ConfigurationProperties(prefix = "test")
//@Component //如果这里添加了注解那么在自动配置类的时候就不用添加@enableConfigurationProperties(HelloProperties.class)注解.
public class Demo {private String msg="default";//现在我们在配置文件写hello.msg=world,因为简单就不再展示;如果那么默认为default.public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}@RequestMapping("/msg")public Object index(){return this.msg;}}

application.yml中配置信息

test:msg: bamboo

访问url获取配置信息返回的值

http://localhost:8080/msg

如果把application.yml中的配置信息注释掉则默认使用default值,否则使用配置信息中的值,以上便是普通配置方式 

SpringBootApplication

SpringBoot 一直是约定优于配置。具体的体现就是在下面的几点

  • maven 项目的配置文件存放在 resources 资源目录下。

  • maven 项目默认编译后的文件放于 target 目录。

  • maven 项目默认打包成 jar 格式。

  • 配置文件默认为 application.yml 或者 application.yaml 或者 application.properties。

  • 默认通过配置文件 spring.profiles.active 来激活配置。

SpringBootApplication 实际上是一个复合注解,其实了不起认为的复合注解就是把一些其他的注解组合起来组装成一个壳子,而外面套的这个壳子,就是复合注解。

其中,@SpringBootConfiguration ,@EnableAutoConfiguration,@ComponentScan三个注解尤为重要。今天我们就来看看这三个注解是干嘛用的。

SpringBootConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;}

它实际上就是一个 @Configuration 注解,这个注解大家应该很熟悉了,加上这个注解就是为了让当前类作为一个配置类交由 Spring 的 IOC 容器进行管理 

ComponentScan 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {@AliasFor("basePackages")String[] value() default {};@AliasFor("value")String[] basePackages() default {};Class<?>[] basePackageClasses() default {};Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;boolean useDefaultFilters() default true;Filter[] includeFilters() default {};Filter[] excludeFilters() default {};boolean lazyInit() default false;@Retention(RetentionPolicy.RUNTIME)@Target({})@interface Filter {FilterType type() default FilterType.ANNOTATION;@AliasFor("classes")Class<?>[] value() default {};@AliasFor("value")Class<?>[] classes() default {};String[] pattern() default {};}}

用于定义 Spring 的扫描路径,等价于在 xml 文件中配置 context:component-scan,假如不配置扫描路径,那么 Spring 就会默认扫描当前类所在的包及其子包中的所有标注了 @Component,@Service,@Controller 等注解的类

EnableAutoConfiguration

这个注解才是实现自动装配的关键,而这个注解,也是一个复合注解,

点进去之后发现,它是一个由 @AutoConfigurationPackage 和 @Import 注解组成的复合注解。

主要的就是这个 import,我们来看看他的源码

@Import 注解其实就是为了去导入一个类AutoConfigurationImportSelector,

@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {//检查自动配置功能是否开启,默认开启if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}//加载自动配置的元信息AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AnnotationAttributes attributes = getAttributes(annotationMetadata);//获取候选配置类List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);//去掉重复的配置类configurations = removeDuplicates(configurations);//获得注解中被exclude和excludeName排除的类的集合Set<String> exclusions = getExclusions(annotationMetadata, attributes);//检查被排除类是否可实例化、是否被自动注册配置所使用,不符合条件则抛出异常checkExcludedClasses(configurations, exclusions);//从候选配置类中去除掉被排除的类configurations.removeAll(exclusions);//过滤configurations = filter(configurations, autoConfigurationMetadata);//将配置类和排除类通过事件传入到监听器中fireAutoConfigurationImportEvents(configurations, exclusions);//最终返回符合条件的自动配置类的全限定名数组return StringUtils.toStringArray(configurations);}

了不起已经在注释中给大家解释了他们每一步的意思

既然我们已经看完了这个 import了,接下来就得看看这个 AutoConfigurationPackage

AutoConfigurationPackage

AutoConfigurationPackage注解的作用是将添加该注解的类所在的package作为自动配置package进行管理。

可以通过 AutoConfigurationPackages 工具类获取自动配置package列表。

当通过注解@SpringBootApplication标注启动类时,已经为启动类添加了@AutoConfigurationPackage注解。

路径为 @SpringBootApplication -> @EnableAutoConfiguration -> @AutoConfigurationPackage。

也就是说当SpringBoot应用启动时默认会将启动类所在的package作为自动配置的package。


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {String[] basePackages() default {};Class<?>[] basePackageClasses() default {};}

我们看到源码中,他 import 了一个 Registrar ,

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));}@Overridepublic Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new PackageImports(metadata));}}

而这个类其实作用就是读取到我们在最外层的 @SpringBootApplication 注解中配置的扫描路径(没有配置则默认当前包下),然后把扫描路径下面的类都加到数组中返回。

自己实现一个自己的自动配置 

xm-common:普通jar项目- src/main    java        BambooServer.java  需要被实例化的服务类        BambooServerProperties.java 配置信息属性类        BmbooServiceAutoConfiguration.java 自动配置类    resources        META-INF/spring.factories 配置自动配置的属性文件demo:普通springboot-web项目

需要实例化的服务类


public class BambooServer {private String name;public String sayServerName(){return "I'm " + name + "! ";}public String getName() {return name;}public void setName(String name) {this.name = name;}}

配置信息对应的属性映射类,需要pom中加入spring-boot-starter依赖

import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "bamboo")
public class BambooServerProperties {private static final String NAME = "bamboo_server0";private String name = NAME;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

自动配置文件

/*** Author: bamboo* Describe: 自动配置类* 根据条件判断是否要自动配置,创建Bean*/
@Configuration
@EnableConfigurationProperties(BambooServerProperties.class)
@ConditionalOnClass(BambooServer.class)//判断BambooServer这个类在类路径中是否存在
@ConditionalOnProperty(prefix = "bamboo",value = "enabled",matchIfMissing = true)
public class BmbooServiceAutoConfiguration {@Autowiredprivate BambooServerProperties mistraServiceProperties;@Bean(name = "bambooServer")@ConditionalOnMissingBean(BambooServer.class)//当容器中没有这个Bean时(BambooServer)就自动配置这个Bean,Bean的参数来自于BambooServerPropertiespublic BambooServer mistraService(){BambooServer mistraService = new BambooServer();mistraService.setName(mistraServiceProperties.getName());return mistraService;}
}

在创建如下路径文件src/main/resources/META-INF/spring.factories

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.bamboo.common.autoconfigure.bamboo.BmbooServiceAutoConfiguration

必须是自动配置类的全路径

mvn install 该项目

创建一个springboot-mvc项目pom依赖上面的jar

@SpringBootApplication
@RestController
//@Import(value = {CorsConfig.class, LogFilter.class}) //跨域,接口访问请求日志
public class DemoApplication {@Autowiredprivate BambooServer bmbooService;public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@RequestMapping("/")public Object index(){return "helll demo"+bmbooService.getName()+DateUtils.getDate();}
}

http://localhost:8080/则返回当前服务的默认值

在applicaton.yml中加,重启刷新则会更新为如下信息

bamboo:name: 测试服务

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

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

相关文章

化工电力系统RFID无线测温技术的重要性。

在现代工业体系中&#xff0c;化工电力系统的安全与效率对于整个生产链的顺畅运行至关重要。在日常工作中,由于设备制造的原因,设备受环境污染的原因、设备长期运行、严重超载运行、触点氧化、电弧冲击等原因造接触电阻增大,因此在运行时往往不断发热,温度不断上升,给设备安全运…

Leetcode Hot100之双指针

1. 移动零 题目描述 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。解题思路 双指针遍历一遍即可解决: 我们定义了两个指针 i 和 j&#xf…

C++ Windows Hook使用

GitHub - microsoft/Detours: Detours is a software package for monitoring and instrumenting API calls on Windows. It is distributed in source code form. /*挂载钩子 setdll /d:C:\Users\g\source\repos\LotTest\Release\lotDll.dll C:\Users\g\source\repos\LotTest…

Java特性之设计模式【访问者模式】

一、访问者模式 概述 在访问者模式&#xff08;Visitor Pattern&#xff09;中&#xff0c;我们使用了一个访问者类&#xff0c;它改变了元素类的执行算法。通过这种方式&#xff0c;元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式&…

WPF三方UI库全局应用MessageBox样式(.NET6版本)

一、问题场景 使用HandyControl简写HC 作为基础UI组件库时&#xff0c;希望系统中所有的MessageBox 样式都使用HC的MessageBox&#xff0c;常规操作如下&#xff1a; 在对应的xxxx.cs 顶部使用using 指定特定类的命名空间。 using MessageBox HandyControl.Controls.Message…

js语法---理解反射Reflect对象和代理Proxy对象

Reflect 基本要点 反射&#xff1a;reflect是一个内置的全局对象&#xff0c;它的作用就是提供了一些对象实例的拦截方法&#xff0c;它的用法和Math对象相似&#xff0c;都只有静态方法和属性&#xff0c;同时reflect也没有构造器&#xff0c;无法通过new运算符构建实例对象&…

xcode和iPhone真机或者watch真机连接问题

1.如果真机是第一次连接xocde&#xff0c;就需要开启真机上的开发者模式&#xff0c;开启开发者模式的方式&#xff1a; iphone/ipad开启方式: 设置 > 隐私与安全 > 开发者模式 > 开启&#xff0c;然后重启就可以了 watch设置&#xff1a;很麻烦&#xff0c;看文章…

数据库异常数据恢复(1)-快速恢复和镜像恢复

(一) 数据库服务器的崩溃和恢复 1. 服务器的修复机制 数据库因为某些原因导致数据库突然异常donw机&#xff0c;为了保证数据库的使用&#xff0c;提供了一些机制进行数据库的恢复 快速恢复&#xff1a;数据库异常down机后重启数据库自己的恢复方式&#xff0c;人工无法干预…

现代谱估计分析信号的功率谱(1)---AR 模型谱估计

本篇文章是博主在通信等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对通信等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在通信领域笔记&#xff1a;…

Spring相关面试题(一)

Spring 1.谈谈你对Spring的理解 难度系数 Spring 是一个开源框架&#xff0c;为简化企业级应用开发而生。Spring 可以是使简单的JavaBean 实现以前只有EJB 才能实现的功能。Spring 是一个 IOC 和 AOP 容器框架。 Spring 容器的主要核心是&#xff1a; 控制反转&#xff08;…

进阶篇06——锁

概述 全局锁 表级锁 表锁 元数据锁 元数据锁是系统自动加的&#xff0c;不需要我们手动执行命令添加。 意向锁 意向锁和元数据锁一样&#xff0c;也是在加行锁的时候自动给表加上相应的意向锁&#xff0c;不需要我们手动添加。 行级锁 行锁 读锁和读锁兼容&#xff0c;写锁…

易舟云财务软件:开启云记账新时代

在数字化浪潮的推动下&#xff0c;财务管理正经历着深刻的变革。易舟云财务软件&#xff0c;作为一款引领时代的云记账平台&#xff0c;以其卓越的功能和便捷的操作&#xff0c;为企业带来了全新的财务管理体验。 云记账&#xff0c;财务管理的未来趋势 云记账&#xff0c;即基…

免费试用【汇通动态域名】体验test.htdns.cn

汇通动态域名下载地址&#xff1a; http://www.htsoft.com.cn/htsoft/htdnssoft.html 下载后汇通动态域名是绿色软件&#xff0c;不用安装&#xff0c;直接运行htdns.exe 点注册 二级域名地方改成您自己要的域名&#xff0c;我输入的是test,点保存&#xff0c;提示让您输入密…

2024年618成交额达7428亿 淘宝京东618交易额数据对比排名

2024年618年中大促已经基本落下帷幕&#xff0c;作为上半年最重要的电商节日&#xff0c;今年的618交易额有多少&#xff1f;今年的交易数据有哪些变化&#xff1f;我们来一起看一下&#xff01; 根据星图监测数据显示&#xff0c;2024年618期间&#xff08;天猫5月20日20: 00-…

Python 中的 Pandas(数据分析与处理)

Pandas 是 Python 中最受欢迎的数据处理库之一&#xff0c;其名字源自于“Panel Data”&#xff08;面板数据&#xff09;的缩写。它提供了三种主要的数据结构&#xff1a;Series &#xff0c; DataFrame &#xff0c; Panel&#xff08;在新版本已经被弃用&#xff09; 数…

海外盲盒APP开发,盲盒出海热!

当下&#xff0c;盲盒作为一种热门的娱乐休闲模式&#xff0c;在全球消费市场中都非常火热&#xff0c;各种热门盲盒商品刚一上线就受到了秒杀&#xff0c;受到了各地年轻消费者的追捧&#xff01; 盲盒全球化对于我国盲盒企业来说是一个新的机会&#xff0c;有助于我国盲盒快…

华为云下Ubuntu20.04中Docker的部署

我想用Docker拉取splash&#xff0c;Docker目前已经无法使用&#xff08;镜像都在国外&#xff09;。这导致了 docker pull 命令的失败&#xff0c;原因是timeout。所以我们有必要将docker的源设置在国内&#xff0c;直接用国内的镜像。 1.在华为云下的Ubuntu20.04因为源的原因…

uniapp+unocss报错Error [ERR_REQUIRE_ESM]: require() of ES Module

uniappvue3使用unocss报错 vite.config.ts代码&#xff1a; import { defineConfig } from "vite"; import uni from "dcloudio/vite-plugin-uni"; import AutoImport from "unplugin-auto-import/vite"; import Unocss from unocss/vite;expo…

Python 基础:文件

目录 一、从文件中读取数据1.1 读取整个文件1.2 逐行读取 二、写入文件2.1 写入空文件2.2 写入多行2.3 附加到文件 遇到看不明白的地方&#xff0c;欢迎在评论中留言呐&#xff0c;一起讨论&#xff0c;一起进步&#xff01; 本文参考&#xff1a;《Python编程&#xff1a;从入…

java-Object 底层实现

### 4. Object类的底层实现 #### 4.1 内存布局 在Java虚拟机中&#xff0c;每个对象都有一个头部&#xff08;Header&#xff09;&#xff0c;包含对象的元数据和同步信息。对象头部包括两个主要部分&#xff1a; - **Mark Word**&#xff1a;用于存储对象的哈希码、GC年龄、…