Spring Boot的自动装配机制?(Spring Boot怎么完成自动装配的?)----面试常问

news2024/11/17 10:45:31

  Spring Boot的自动装配机制?(Spring Boot怎么完成自动装配的?)

目录

一、概念版(重要)

二、实操版 

1. 依赖管理 (pom.xml导坐标)

2. 自动配置类

2.1 @SpringBootApplication 注解 

2.2 @EnableAutoConfiguration 

2.3 @Import({AutoConfigurationImportSelector.class})

2.3.1  条件注解(Conditional Annotations) 

2.4 META-INF/spring.factories 文件


一、概念版(重要

      答:自动装配,简单来说就是自动去把第三方组件的Bean转载到IOC容器中,不需要开发人员再去手写Bean相关的一个配置。在Spring Boot应用里面,只需要在启动类上加上@SpringBootApplication注解就可以去实现自动装配。@SpringBootApplication是一个复合注解,真正去实现自动配置的是@EnableAutoConfiguration注解。

       自动装配主要依靠三个核心的关键技术。

     第一个,引入Starter启动依赖组件的时候,这个组件里面必须要包含一个@Configuation配置类,而在这个配置类里面,我们要通过@Bean注解去声明需要装配到IOC容器里面的Bean对象。

       第二个,这个配置类是放在第三方jar包里面的,然后通过Spring Boot中约定优于配置的理念去把这个配置类的全路径放在Classpath:/META-INF/spring.factories文件里面。这样的话,Spring Boot就可以知道第三方jar包里面这个配置类的位置。这个步骤主要是用到了Spring里面的SpringFactoriesLoader来完成的。

       第三个,Spring Boot 获取到所有第三方 jar 包中声明的配置类以后,再通过Spring提供的ImportSelector这样一个接口,来实现对这些配置类的动态加载,从而去完成自动装配这样一个动作。

       在我看来,Spring Boot是约定优于配置这一理念下的一个产物。所以在很多地方,都会看到这一类的思想,它的出现可以让开发人员更加聚焦的在业务代码的编写上,而不需要去关心和业务无关的配置。其实,自动装配的思想在SpringFramework 3.x版本里面的@Enable注解就已经有了实现的一个雏形。@Enable注解是一个模块驱动的意思,也就是说我们只需要增加@Enable注解就能自动打开某个功能,而不需要针对这个功能去做Bean的配置。@Enable注解的底层也是去帮我们自动完成这样一个模块相关Bean的注入的。

       以上就是我对Spring Boot的自动装配的一个理解。

注:约定优于配置理念是什么?

 约定优于配置(Convention Over Configuration) 是一种软件开发理念,指在软件开发中,遵循一些既定的约定和默认规则,从而减少开发人员需要进行的显式配置。

例如,在某些框架或技术中,可能会有以下的约定:

  • 项目的目录结构:按照特定的层次结构存放代码、配置文件、资源文件等。
  • 类和方法的命名规则:遵循一定的命名规范,以便框架能够自动识别和处理。
  • 配置文件的默认位置和格式:框架会默认在特定的位置查找具有特定格式的配置文件。

        通过遵循这些约定,开发人员无需花费大量时间和精力来详细配置每个细节,提高了开发效率,减少了配置错误的可能性,同时也使得代码和项目结构更加规范和易于理解。

        以 Spring Boot 为例,如果遵循了其约定,比如将应用的配置文件命名为 application.properties 或 application.yml 并放在特定的位置,框架就能自动识别并加载相应的配置,而无需开发人员显式地告诉框架配置文件的位置和名称。

二、实操版 

        Spring Boot 的自动配置(Auto-configuration)是其核心特性之一,它极大地简化了基于 Spring 的应用开发。  自动配置的工作原理主要依赖于“条件注解”(如 @Conditional)和 Spring Factories(META-INF/spring.factories 文件)

        以下是 Spring Boot 自动配置的基本步骤和原理:

1. 依赖管理 (pom.xml导坐标)

        首先,需要添加spring-boot-starter-web 依赖,Spring Boot 就会自动配置 Tomcat 和 Spring MVC。

# pom.xml
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        其次,在配置文件中写下Redis的配置就可以调用Redis的服务 

 

2. 自动配置类

自动配置类通常使用 @Configuration 注解进行标注。在配置类中,可以通过 @Bean 方法定义要注入到 IOC 容器中的 Bean 对象。 

例如:

2.1 @SpringBootApplication 注解 

首先进入@SpringBootApplication注解的源代码:

@SpringBootApplication 是一个在 Spring Boot 项目中常用的复合注解。

它组合了以下三个主要的注解功能:

  1. @SpringBootConfiguration表明这是一个 Spring Boot 的配置类,继承自 @Configuration ,用于定义 Bean 和配置相关的逻辑。

  2. @EnableAutoConfiguration开启 Spring Boot 的自动配置功能。它会根据项目所依赖的库和配置来自动配置应用程序所需的各种组件和设置。

  3. @ComponentScan:用于扫描和注册项目中的组件(例如 @Component 、@Service 、@Repository 等注解标注的类),使其能够被 Spring 容器管理。

总的来说,使用 @SpringBootApplication 注解可以简化 Spring Boot 项目的配置,使开发更加便捷高效。通常将其添加在项目的主启动类上

例如:自动配置类

package com.apesource.springbootstarter04;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import redis.clients.jedis.Jedis;

@SpringBootApplication
public class SpringbootStarter04Application {

    public static void main(String[] args) {
       ConfigurableApplicationContext context =  SpringApplication.run(SpringbootStarter04Application.class, args);


        Jedis bean1 = context.getBean(Jedis.class);
        System.out.println(bean1);
    }

}

 

2.2 @EnableAutoConfiguration 

 其次进入@EnableAutoConfiguration注解的源代码:

        在Spring Boot 项目的主启动类上,通常会添加@SpringBootApplication 注解。这是一个复合注解,其中关键的是 @EnableAutoConfiguration 注解,它开启了自动配置的功能。主要组合应用以下两个注解:

  1. @AutoConfigurationPackage,将项目src中main包下的所有组件注册到容器中,例如标注了Component注解的类等等

  2. @Import({AutoConfigurationImportSelector.class}),是自动装配的核心。 注解用于向 Spring 容器中导入指定的组件或配置类。

2.3 @Import({AutoConfigurationImportSelector.class})

选取部分 AutoConfigurationImportSelector类源代码

AutoConfigurationImportSelector 是 Spring Boot 中一个重要的类,它实现了ImportSelector接口,用于实现自动配置的选择和导入。具体来说,它通过分析项目的类路径和条件来决定应该导入哪些自动配置类。主要工作是:

  1. 扫描类路径: 在应用程序启动时,AutoConfigurationImportSelector 会扫描类路径上的 META-INF/spring.factories 文件,这个文件中包含了各种 Spring 配置和扩展的定义。在这里,它会查找所有实现了 AutoConfiguration 接口的类,具体的实现为getCandidateConfigurations方法。
  2. 条件判断: 对于每一个发现的自动配置类,AutoConfigurationImportSelector 会使用条件判断机制(通常是通过 @ConditionalOnXxx 注解)来确定是否满足导入条件。这些条件可以是配置属性、类是否存在、Bean是否存在等等。
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    
    // ... (其他方法和属性)

  // 获取所有符合条件的类的全限定类名,例如RedisTemplate的全限定类名(org.springframework.data.redis.core.RedisTemplate;),这些类需要被加载到 IoC 容器中。
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		// 扫描类路径上的 META-INF/spring.factories 文件,获取所有实现了 AutoConfiguration 接口的自动配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);

		// 过滤掉不满足条件的自动配置类,比如一些自动装配类
		configurations = filter(configurations, annotationMetadata, attributes);

		// 排序自动配置类,根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序
		sort(configurations, annotationMetadata, attributes);

		// 将满足条件的自动配置类的类名数组返回,这些类将被导入到应用程序上下文中
		return StringUtils.toStringArray(configurations);
	}

	// ... (其他方法)
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		// 获取自动配置类的候选列表,从 META-INF/spring.factories 文件中读取
		// 通过类加载器加载所有候选类
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());

		// 过滤出实现了 AutoConfiguration 接口的自动配置类
		configurations = configurations.stream()
				.filter(this::isEnabled)
				.collect(Collectors.toList());

		// 对于 Spring Boot 1.x 版本,还需要添加 spring-boot-autoconfigure 包中的自动配置类
		// configurations.addAll(getAutoConfigEntry(getAutoConfigurationEntry(metadata)));
		return configurations;
	}

	// ... (其他方法)
	protected List<String> filter(List<String> configurations, AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		// 使用条件判断机制,过滤掉不满足条件的自动配置类
		configurations = configurations.stream()
				.filter(configuration -> isConfigurationCandidate(configuration, metadata, attributes))
				.collect(Collectors.toList());
		return configurations;
	}

	// ... (其他方法)
	protected void sort(List<String> configurations, AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		// 根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序对自动配置类进行排序
		configurations.sort((o1, o2) -> {
			int i1 = getAutoConfigurationOrder(o1, metadata, attributes);
			int i2 = getAutoConfigurationOrder(o2, metadata, attributes);
			return Integer.compare(i1, i2);
		});
	}
  
  	// ... (其他方法)

}
2.3.1  条件注解(Conditional Annotations) 


Spring Boot 使用了一系列条件注解来决定是否应用特定的配置。例如:

  • @ConditionalOnClass:只有当指定的类在类路径中存在时,才会激活相关配置。
  • @ConditionalOnProperty:根据配置文件中的属性值来决定是否应用配置。

 例如:自定义主配置文件中RedisProperties文件必须存在才能执行

package com.apesource;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoconfiguration {
    @Bean
    public Jedis jedis(RedisProperties redisProperties){
        return new Jedis(redisProperties.getHost(),redisProperties.getPort());
    }
}

2.4 META-INF/spring.factories 文件

Spring Boot 会扫描项目及依赖的 JAR 包中的 META-INF\spring.factories文件。这个文件中定义了自动配置类的全限定名,Spring Boot 可以根据这些信息找到并加载相应的配置类。

  例如:resources\META-INF\spring.factories

# META-INF\spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.apesource.RedisAutoconfiguration

        总的来说,Spring Boot 的自动装配机制通过依赖管理、注解、条件判断、配置类扫描和注册等一系列操作,实现了根据项目的具体情况自动完成组件的配置和加载。

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

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

相关文章

基于node.js的宠物寄存管理系统,基于express的宠物寄存系统

摘 要 伴随着社会以及科学技术的发展&#xff0c;互联网已经渗透在人们的身边&#xff0c;网络慢慢的变成了人们的生活必不可少的一部分&#xff0c;紧接着网络飞速的发展&#xff0c;系统管理这一名词已不陌生&#xff0c;越来越多的宠物店等机构都会定制一款属于自己个性化…

2.8销毁窗口

目录 1.实验原理 2.实验代码 3.运行结果 1.实验原理 销毁某一个指定名称的窗口 destoryWindow 函数原型 Destroys a window.void destroyWindow(const string& winname)&#xff1b;含义 功能: 销毁指定名称的窗口。 参数: const string& winname: 一个字符串&am…

香港租云服务器多少钱一台?

香港租云服务器多少钱一台&#xff1f;香港云服务器的租用价格因配置、带宽、服务等级等因素而异&#xff0c;从数百元到数千元不等。例如&#xff0c;入门级服务器的价格在数百元至一千元之间&#xff0c;适用于个人网站、小型博客等低流量应用。标准型服务器的价格在一千元至…

电商人必看!4招拿捏消费者心理,没有卖不出去的产品

在竞争激烈的电商领域&#xff0c;产品如何脱颖而出&#xff0c;成为消费者心中的首选&#xff0c;不仅依赖于产品的质量与性价比&#xff0c;更在于如何精准把握并巧妙运用消费者心理。今天&#xff0c;我们就来探讨4个关键策略&#xff0c;结合选品建议&#xff0c;帮助电商人…

欠债还钱 天经地义李秘书专业写作:这是一篇涉借款纠纷的民事起诉状

欠债还钱 天经地义 李秘书专业写作&#xff1a;这是一篇涉借款纠纷的民事起诉状 &#xff08;精品范文&#xff09; 民 事 诉 状 原告&#xff1a;李某军&#xff0c;男&#xff0c;现年46岁&#xff0c;无业&#xff0c;现住黑龙江省大兴安岭地区漠河市汉东路阳和门。 被告…

儿童可以用挖耳勺吗?六大挑选妙招需掌握!

耳垢会随着人体的运动量增加&#xff0c;1岁以下的儿童运动量较小&#xff0c;可以不用经常掏耳朵&#xff0c;但随着年龄增长&#xff0c;耳垢也会增多&#xff0c;这时可以适当地给儿童掏耳勺。但掏耳朵的工具要选对&#xff0c;目前市面上不少宣称是儿童专用的掏耳工具&…

汇凯金业:清洗黄金首饰的方法

黄金首饰&#xff0c;作为我们日常生活中常见的饰品&#xff0c;不仅能够提升我们的穿着品味&#xff0c;更彰显了我们的经济实力。然而&#xff0c;黄金首饰戴久了&#xff0c;难免会出现一些污渍&#xff0c;甚至失去原有的光泽。这时候&#xff0c;很多人会选择去专业的珠宝…

【MySQL】SQL语句执行流程

目录 一、连接器 二、 查缓存 三、分析器 四、优化器 五、执行器 一、连接器 学习 MySQL 的过程中&#xff0c;除了安装&#xff0c;我们要做的第一步就是连接上 MySQL 在一开始我们都是先使用命令行连接 MySQL mysql -h localhost -u root -p 你的密码 使用这个命令…

Qt (9)【Qt窗口 —— 如何在窗口中创建菜单栏和工具栏】

阅读导航 引言一、Qt窗口简介二、如何在窗口中创建菜单栏1. 创建菜单栏2. 在菜单栏中添加菜单3. 创建菜单项4. 在菜单项之间添加分割线 三、如何在窗口中创建工具栏1. 创建工具栏2. 设置停靠位置3. 设置浮动属性4. 设置移动属性 引言 在上一篇文章中&#xff0c;我们深入探讨了…

掌握 BM25:深入了解算法及其在 Milvus 中的应用

我们可以通过 Milvus 轻松实现 BM25 算法&#xff0c;将文档和查询转化为稀疏向量。然后&#xff0c;这些稀疏向量可用于向量搜索&#xff0c;根据特定查询找到最相关的文档。 信息检索算法在搜索引擎中非常重要&#xff0c;可确保搜索结果与用户的查询相关。 想象一下&#…

Vue2中watch与Vue3中watch对比和踩坑

上一节说到了 computed计算属性对比 &#xff0c;虽然计算属性在大多数情况下更合适&#xff0c;但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法&#xff0c;来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时&#…

conda环境下在pycharm中调试scrapy项目

前提条件 已经创建好了conda环境已经安装好了scrapy框架项目初始化完成 编写一个爬虫脚本 import scrapyclass StackOverflowSpider(scrapy.Spider):name stackoverflowstart_urls [http://stackoverflow.com/questions?sortvotes]def parse(self, response):print("…

阿一网络安全实战演练之利用 REST URL 中的服务器端参数污染

所需知识 要解决这个实验室问题&#xff0c;您需要了解以下内容&#xff1a; 如何确定用户输入是否包含在服务器端的 URL 路径或查询字符串中。如何使用路径遍历序列尝试更改服务器端请求。如何查找 API 文档。 这些内容在我们的 API 测试学院主题中有涵盖。 进入实验室 研…

终极解决CondaValueError: Malformed version string ‘~’: invalid character(s)问题

conda 创建环境时出现&#xff1a; Solving environment: failed CondaValueError: Malformed version string ‘~’: invalid character(s)以下两种方法都不行时&#xff1a; 原因一&#xff1a; 添加的镜像源中&#xff0c;清华镜像源是https&#xff08;错误&#xff09;&a…

软件测试 - 测试分类(静态测试、动态测试、白盒测试、黑盒测试、灰盒测试、单元测试、集成测试、系统测试、验收测试等)

一、为什么要对软件测试进⾏分类&#xff1f; 软件测试是软件⽣命周期中的⼀个重要环节&#xff0c;具有较⾼的复杂性&#xff0c;对于软件测试&#xff0c;可以从不同的⻆度 加以分类&#xff0c;使开发者在软件开发过程中的不同层次、不同阶段对测试⼯作进⾏更好的执⾏和管理…

R语言管道操作详解-高效编程

引言 R语言是一种广泛应用于统计分析和图形表示的编程语言和软件环境。随着数据分析和数据科学的发展&#xff0c;R语言的管道操作符已经成为提高代码可读性和效率的重要工具。本文将详细介绍R语言中的管道操作符&#xff0c;包括它们的用途、语法和一些实用的示例。 目录 引…

手写签名怎么变成电子签名?

教大家一个快速生成有效电子签名的方法&#xff01;&#xff08;有效电子签名即通过正轨平台绑定了CA数字证书、防伪防盗的签名&#xff09; 1.登录【微签】&#xff0c;点击【自己签】。 2.点【添加文件】&#xff0c;上传需要签名的电子文件&#xff08;格式不限&#xff09;…

一起学习LeetCode热题100道(46/100)

46.二叉树展开为链表(学习) 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。 展开后的单链表应该与二叉树 先序遍历…

Affine Transformations仿射变换

什么是仿射变换 仿射变换&#xff08;Affine Transformation&#xff09;是数学和计算机图形学中的一种线性变换&#xff0c;它包括了平移、旋转、缩放、剪切等操作。仿射变换保留了几何图形的“仿射性质”&#xff0c;即平行线在变换后仍然平行&#xff0c;线性组合在变换后仍…

电机预测性维护模组

设备简介 本模组为了对电机进行预测性运维而开发&#xff0c;可以采集电机的 3 路加速度振动传感器、3 路电流&#xff08;电机供电互感器输出信号&#xff09;、1 路转速&#xff08;电机转速&#xff09;、8 路温度&#xff08;PT100 温度传感器&#xff09;。 模组计算振动…