springboot中@bean注解的创建和使用

bean的创建顺序

在Spring Boot中,当一个配置类(使用@Configuration注解的类)中定义了多个bean时,这些bean的创建顺序并不完全由它们在类中的声明顺序决定。Spring框架在创建和管理bean时,遵循了复杂的依赖注入和生命周期管理规则,这些规则决定了bean的创建和初始化顺序。

以下是文心一言给出的一些影响bean创建顺序的主要因素(我直接复制过来):

  • 依赖关系:Spring容器会根据bean之间的依赖关系来决定创建顺序。如果一个bean依赖于另一个bean,那么被依赖的bean会首先被创建。Spring通过构造函数、setter方法或字段注入等方式来识别这些依赖关系。
  • @DependsOn注解:你可以使用@DependsOn注解来显式指定一个bean依赖于其他一个或多个bean。被@DependsOn注解指定的bean会在当前bean之前被创建。
  • @Order或实现Ordered接口:虽然这些主要用于排序多个相同类型的bean(例如,多个实现了同一接口的bean),但它们在某些情况下也可能间接影响bean的创建顺序,尤其是当这些bean之间存在依赖关系时。
  • @Bean的注册顺序:在配置类中,虽然bean的声明顺序不是决定性因素,但在没有其他依赖关系或显式排序的情况下,* Spring可能会按照它们在配置类中声明的顺序来创建bean。但是,这种顺序并不是严格保证的,特别是当存在复杂的依赖关系时。
  • 初始化回调:Spring提供了几种初始化回调方法(如@PostConstruct注解的方法或实现了InitializingBean接口的afterPropertiesSet方法),这些方法在bean的所有必要属性被容器设置之后被调用。这些回调的执行顺序也受bean之间的依赖关系影响。
  • 懒加载(Lazy Initialization):如果bean被标记为懒加载(通过@Lazy注解或全局配置),那么它只会在首次被请求时创建,这可能会影响bean的创建顺序。
  • 总结来说,Spring Boot中配置类中多个bean的创建顺序主要由bean之间的依赖关系决定,而不仅仅是它们在配置类中的声明顺序。因此,在设计应用时,应该尽量避免对bean创建顺序的隐式依赖,而是通过显式的依赖关系或配置来管理bean的创建和初始化顺序。

bean注解的创建

首先这个注解在方法上使用,也可以在注解使用,这里只介绍在方法上使用的情况
在这里插入图片描述
在方法上使用很简单,只需要把它放在方法上就行
e.g

    @Bean@ConfigurationProperties("spring.datasource.druid.master")public DataSource masterDataSource(DruidProperties druidProperties){DruidDataSource dataSource = DruidDataSourceBuilder.create().build();return druidProperties.dataSource(dataSource);}
  • 这样如果在类中当做类属性使用,我们直接使用@Autowired注解注入就好了,

那如果是下面这样呢,这个

    @Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource(DataSource dataSource){Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER.name(), dataSource);setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");return new DynamicDataSource(dataSource, targetDataSources);}

这样根据基于springboot的自动装配类型中的基于类型装配,可以找到我们上面创建的那个DataSource类型的bean

spring的依赖注入

实际上在Spring框架中,当你使用@Bean注解来声明一个bean的创建方法时,该方法中的参数并不是直接从某个地方“自动”获取的,而是根据Spring的依赖注入(DI)机制来解决的。Spring容器在创建bean时,会分析@Bean方法中的参数,并尝试通过以下几种方式来解决这些参数的依赖:

  • 自动装配(Autowiring):
  1. 基于类型(byType):Spring会尝试在容器中查找与参数类型相匹配的bean。如果容器中只有一个bean匹配该类型,Spring会自动注入这个bean。如果有多个bean匹配,并且没有使用@Qualifier注解来指定具体的bean名称,那么Spring会抛出异常,因为它不知道应该注入哪一个bean。
  2. 基于名称(byName):如果你的@Bean方法参数名与容器中某个bean的名称相匹配,并且Spring的配置中启用了基于名称的自动装配(这通常是默认行为),那么Spring会尝试注入这个bean。不过,需要注意的是,在@Bean方法中使用基于名称的自动装配并不是非常直观,因为@Bean方法的参数名在编译后可能会被优化或更改,这取决于JVM和编译器的设置。因此,更推荐使用基于类型的自动装配。
  • 通过方法参数中的注解:
  1. 如果@Bean方法的参数上使用了如@Qualifier、@Value等注解,Spring会根据这些注解来解析参数的值。例如,@Qualifier注解可以用来指定应该注入哪个bean(在有多个候选bean的情况下)。@Value注解则通常用于注入配置文件中的值(如属性文件中的值)。
  2. 通过构造函数或setter方法:
    需要注意的是,虽然这里讨论的是@Bean方法中的参数,但通常我们不会在@Bean方法内部直接创建依赖对象(即参数所代表的bean)。相反,我们会让Spring通过构造函数或setter方法将这些依赖注入到我们的bean中。然而,对于@Bean方法本身,其参数是通过上述的依赖注入机制来解决的。
  3. Java配置和@Configuration类:
    在@Configuration注解的类中,@Bean方法之间可以相互引用,因为Spring会确保在调用一个@Bean方法之前,它所依赖的所有bean都已经被创建和初始化。这种机制使得我们可以在@Bean方法中引用其他@Bean方法声明的bean。
    总之,@Bean方法中的参数值是通过Spring的依赖注入机制来解决的,这通常涉及到基于类型或名称的自动装配,以及方法参数上的注解。

bean的名称

  • 每个bean都有一个名称,那使用@Bean注解产生的bean在容器中的bean的名称什么,在下面有两个DataSource类型的bean
@Bean@ConfigurationProperties("spring.datasource.druid.master")public DataSource masterDataSource(DruidProperties druidProperties){DruidDataSource dataSource = DruidDataSourceBuilder.create().build();return druidProperties.dataSource(dataSource);}/*** 这里bean没有指定名称那这个bean在容器中的名称就 是方法名 "slaveDataSource"* @param druidProperties* @return*/@Bean@ConfigurationProperties("spring.datasource.druid.slave")@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")public DataSource slaveDataSource(DruidProperties druidProperties){DruidDataSource dataSource = DruidDataSourceBuilder.create().build();return druidProperties.dataSource(dataSource);}

在@bean注解中有个name参数,根据描述我们可以看出name值就是这个bean的名称,其中If left unspecified, the name of the bean is the name of the annotated method,表示如果没有指定,那这个bean的名称就是@Bean注解所注释的方法的名称,所以上面两个bean的名称分别是masterDataSource 和 slaveDataSource
在这里插入图片描述

  • 如果指定了默认名称,那么这个bean在容器里就叫dynamicDataSource
    @Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource(DataSource masterDataSource){Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");return new DynamicDataSource(masterDataSource, targetDataSources);}

那么参数中 public DynamicDataSource dataSource(DataSource masterDataSource)中的形参masterDataSource来自哪里呢,实际上它是spring从容器中找一个类型为DataSource,名为 masterDataSource的bean,如果把这里改成下面这样就会报错,因为容器中现在有两个DataSource类型的bean,masterDataSource 和 slaveDataSource,这里形参名叫做dataSource,spring根据名称找不到,根据类型能找到两个,不知道注入哪一个,就会报错

@Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource1(DataSource dataSource){Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER.name(), dataSource);setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");return new DynamicDataSource(dataSource, targetDataSources);}

这个时候@Qualifier注解就可以使用了,可以用@Qualifier注解指定bean,将masterDataSource的值 赋值到形参 dataSource

 /**** 这里的形参 dataSource指的容器中DataSource类型的 名为dataSource 的 bean* 但是这里面容器里面没有这个bean,就可以用@Qualifier注解指定bean,将masterDataSource的值 赋值到形参 dataSource*/@Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource1(@Qualifier("masterDataSource") DataSource dataSource){Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER.name(), dataSource);setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");return new DynamicDataSource(dataSource, targetDataSources);}

这里实际上还有个@Primary注解,假如有多个相同类型的bean,可以使用@Primary来标明优先用那个bean,但是同一种类型的bean,只能有一个使用@Primary注解,实际上DynamicDataSource是DataSource的子类,所以实际上它们是同一种bean,所以只能有一个@Primary注解

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

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

相关文章

在Windows中使用开源高性能编辑器Zed(持续更新)

简介 “Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter. It’s also open source.” “Zed是一款高性能的支持多人协作的代码编辑器&#xff0c;由Atom和Tree-sitter的创建者开发。它也是开源的。” Zed主打“高性能”&…

为什么选择开放式耳机?悠律凝声环开放式耳机体验

开放式耳机相对于其他传统耳机优势有以下几点&#xff1a; 配戴舒适性更好&#xff1a;由于开放式耳机的背面是开放的&#xff0c;空气可以自由流动&#xff0c;减少了耳朵的闷热感。长时间佩戴时更加舒适。&#xff0c;而传统入耳式耳机一般都是塞入耳道&#xff0c;久戴会胀…

Java中的 this 关键字是什么意思? this() 又是什么?

目录 问题问题一&#xff1a;什么是this关键字?问题二&#xff1a;什么是this()&#xff1f; 问题 问题一&#xff1a;什么是this关键字? 定义&#xff1a;this 代表当前对象。这个定义比较抽象&#xff0c;举例来回答。 思考一个问题&#xff1a;如果没有 this 会怎样&…

鸿蒙开发学习笔记2

一、class 类 类是用于 创建对象模版。同时类声明也会引入一个 新类型&#xff0c;可定义其 实例属性、方法 和 构造函数。 // 类名 首字母大写&#xff08;规范&#xff09; class 类名 {// 1、实例属性&#xff08;字段&#xff09;// 2、构造函数// 3、方法 }1、属性&…

如何追踪ping连接中的所有路由器的数量和IP

如何快速判断ping连接经过的路由器个数和IP&#xff1f; 方法一&#xff1a; ping命令会返回一个TTL&#xff0c;TTL&#xff08;Time To Live&#xff09;存活时间&#xff0c;一般初始值为64&#xff0c;每经过一个路由器就减一&#xff0c;当TTL为0时丢弃网络包&#xff0…

“Numpy数据分析与挖掘:高效学习重点技能“

目录 # 开篇 # 补充 zeros & ones eye 1. numpy数组的创建 1.1 array 1.2 range 1.3 arange 1.4 常见的数据类型 1.5 astype 1.6 random.random() & round 2. numpy数组计算和数组计算 2.1 reshape 2.2 shape 2.3 将一维数组变成多维数组 2.4 指定一维…

0010基于免疫遗传算法的配送中心选址

免疫优化算法&#xff08;Immune Optimization Algorithm, IOA&#xff09;在物流配送中心选址中的应用是通过模拟免疫系统的进化过程来解决选址优化问题。物流配送中心选址问题涉及到如何在给定区域内选择最优的位置&#xff0c;以最大化服务覆盖并最小化运输成本。 免疫优化…

我的FPGA

1.安装quartus 2.更新usb blaster驱动 3.新建工程 1.随便找一个文件夹&#xff0c;里面新建demo文件夹&#xff0c;表示一个个工程 在demo文件夹里面&#xff0c;新建src&#xff08;源码&#xff09;&#xff0c;prj&#xff08;项目&#xff09;&#xff0c;doc&#xff…

压缩感知2——算法模型

采集原理 其中Y就是压缩后的信号表示(M维)&#xff0c;Φ表示采集的测量矩阵&#xff0c;可以是一个随机矩阵&#xff0c;X代表原始的数字信号&#xff08;N维&#xff09;。 常见的测量矩阵——随机高斯矩阵 随机伯努利矩阵 稀疏随机矩阵等&#xff0c;矩阵需要满足与信号的稀…

AWS无服务器 应用程序开发—第十七章 Application Composer

Application Composer 是 AWS 提供的一种可视化工具,用于设计和构建无服务器应用程序。它通过拖放界面简化了无服务器架构的创建过程,使开发者能够更直观地设计和配置应用程序的各个组件。 主要功能 可视化设计 通过拖放界面,开发者可以轻松地添加和配置 AWS 资源,如 L…

2-29 基于matlab的CEEMD

基于matlab的CEEMD&#xff08;Complementary Ensemble Empirical Mode Decomposition&#xff0c;互补集合经验模态分解&#xff09;&#xff0c;先将数据精心ceemd分解&#xff0c;得到imf分量&#xff0c;然后通过相关系数帅选分量&#xff0c;在求出他们的样本熵的特征。用…

【深度学习】第5章——卷积神经网络(CNN)

一、卷积神经网络 1.定义 卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;是一种专门用于处理具有网格状拓扑结构数据的深度学习模型&#xff0c;特别适用于图像和视频处理。CNN 通过局部连接和权重共享机制&#xff0c;有效地减少了参数数量&#x…

使用OpencvSharp实现人脸识别

在网上有很多关于这方面的博客&#xff0c;但是都没有说完整&#xff0c;按照他们的博客做下来代码都不能跑。所以我就自己写个博客补充一下 我这使用的.NET框架版本是 .NetFramework4.7.1 使用Nuget安装这两个程序包就够了&#xff0c;不需要其他的配置 一定要安装OpenCvSha…

在亚马逊云科技AWS上利用SageMaker机器学习模型平台搭建生成式AI应用(附Llama大模型部署和测试代码)

项目简介&#xff1a; 接下来&#xff0c;小李哥将会每天介绍一个基于亚马逊云科技AWS云计算平台的全球前沿AI技术解决方案&#xff0c;帮助大家快速了解国际上最热门的云计算平台亚马逊云科技AWS AI最佳实践&#xff0c;并应用到自己的日常工作里。本次介绍的是如何在Amazon …

802.11漫游流程简单解析与笔记_Part2_05_wpa_supplicant如何通过nl80211控制内核开始关联

最近在进行和802.11漫游有关的工作&#xff0c;需要对wpa_supplicant认证流程和漫游过程有更多的了解&#xff0c;所以通过阅读论文等方式&#xff0c;记录整理漫游相关知识。Part1将记录802.11漫游的基本流程、802.11R的基本流程、与认证和漫游都有关的三层秘钥基础。Part1将包…

220V降5V芯片输出电压电流封装选型WT

220V降5V芯片输出电压电流封装选型WT 220V降5V恒压推荐&#xff1a;非隔离芯片选型及其应用方案 在考虑220V转低压应用方案时&#xff0c;以下非隔离芯片型号及其封装形式提供了不同的电压电流输出能力&#xff1a; 1. WT5101A&#xff08;SOT23-3封装&#xff09;适用于将2…

【实战场景】大文件解析入库的方案有哪些?

【实战场景】大文件解析入库的方案有哪些&#xff1f; 开篇词&#xff1a;干货篇&#xff1a;分块解析内存映射文件流式处理数据库集群处理分布式计算框架 总结篇&#xff1a;我是杰叔叔&#xff0c;一名沪漂的码农&#xff0c;下期再会&#xff01; 开篇词&#xff1a; 需求背…

14-57 剑和诗人31 - LLM/SLM 中的高级 RAG

​​​ 首先确定几个缩写的意思 SLM 小模型 LLM 大模型 检索增强生成 (RAG) 已成为一种增强语言模型能力的强大技术。通过检索和调整外部知识&#xff0c;RAG 可让模型生成更准确、更相关、更全面的文本。 RAG 架构主要有三种类型&#xff1a;简单型、模块化和高级 RAG&…

Git安装使用教程

# 《Git 操作使用教程》 一、Git 简介 Git 是一个分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或小或大的项目。它让开发者可以轻松地跟踪代码的更改、与团队成员协作&#xff0c;并管理项目的不同版本。 二、安装 Git 在 Windows 系统上&#xff0c;可以从 Git 官…

无法连接Linux远程服务器的Mysql,解决办法

问题描述 如果是关闭虚拟机之后&#xff0c;二次打开无法连接Mysql&#xff0c;则可尝试一下方法进行解决 解决方法 关闭虚拟机的防火墙 1&#xff1a;查看防火墙状态 systemctl status firewalld 一下显示说明防火墙是启动的状态 2&#xff1a;关闭防火墙 systemctl st…