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

news2024/9/20 5:51:46

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")
    @Primary
    public 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")
    @Primary
    public 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")
    @Primary
    public 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")
    @Primary
    public 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.coloradmin.cn/o/1911935.html

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

相关文章

什么,有狗快跑!慢着,这次手把手教你怎么过安全狗!(sql注入篇)

前言 在记忆里上次绕安全狗还是在上次&#xff0c;开开心心把自己之前绕过狗的payload拿出来&#xff0c;发现全部被拦截了&#xff0c;事情一下子就严肃起来了&#xff0c;这就开整。 环境 本次环境如下sqli-lab的sql注入靶场 网站安全狗APACHE版V4.0版本的最高防护等级绕过…

北京大学长安汽车发布毫米波与相机融合模型RCBEVDet:最快能达到每秒28帧

Abstract 三维目标检测是自动驾驶中的关键任务之一。为了在实际应用中降低成本&#xff0c;提出了利用低成本的多视角相机进行3D目标检测&#xff0c;以取代昂贵的LiDAR传感器。然而&#xff0c;仅依靠相机很难实现高精度和鲁棒性的3D目标检测。解决这一问题的有效方法是将多视…

思维+数学,CF 1138B - Circus

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1138B - Circus 二、解题报告 1、思路分析 设第一组会小丑和杂技的人数分别为x1, y1 第二组会小丑和杂技的人数分别为x2, y2 显然根据要求有&#xff1a; x1 y2 > x1 x2 x2 y2 上式说明第二组每…

【QT中实现摄像头播放、以及视频录制】

学习分享 1、效果图2、camerathread.h3、camerathread.cpp4、mainwindow.h5、mainwindow.cpp6、main.cpp 1、效果图 2、camerathread.h #ifndef CAMERATHREAD_H #define CAMERATHREAD_H#include <QObject> #include <QThread> #include <QDebug> #include &…

OpenFWI代码

重点关注文章第4部分 一、代码模块概览 这一部分了解代码主要实现的功能有哪些。 二、运行 这一部分关注如何跑通。 三、数据集 12个数据集&#xff08;11个2D1个3D&#xff09; 对计算机而言&#xff0c;上述输入、输出维度大小是按次数定义的。 以“Vel&#xff0c;F…

Celery,一个实时处理的 Python 分布式系统

大家好&#xff01;我是爱摸鱼的小鸿&#xff0c;关注我&#xff0c;收看每期的编程干货。 一个简单的库&#xff0c;也许能够开启我们的智慧之门&#xff0c; 一个普通的方法&#xff0c;也许能在危急时刻挽救我们于水深火热&#xff0c; 一个新颖的思维方式&#xff0c;也许能…

Spring-AOP(二)

作者&#xff1a;月下山川 公众号&#xff1a;月下山川 1、什么是AOP AOP&#xff08;Aspect Oriented Programming&#xff09;是一种设计思想&#xff0c;是软件设计领域中的面向切面编程&#xff0c;它是面向对象编程的一种补充和完善&#xff0c;它以通过预编译方式和运行期…

MySQL:TABLE_SCHEMA及其应用

MySQL TABLE_SCHEMA及其应用 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/ar…

持久化存储与设备环境查询的最佳实践

ArkUI框架中的PersistentStorage和Environment 在ArkUI框架中&#xff0c;持久化存储和设备环境查询是应用开发中不可或缺的两个重要功能。在本文中&#xff0c;我们将深入了解框架提供的PersistentStorage和Environment&#xff0c;它们的用途、限制条件以及在应用开发中的使…

SDIO CMD 数据部分 CRC 计算规则

使用的在线 crc 计算工具网址&#xff1a;http://www.ip33.com/crc.html CMD CRC7 计算 如下图为使用逻辑分析仪获取的SDIO读写SD卡时&#xff0c;CMD16指令发送的格式&#xff0c;通过逻辑分析仪总线分析&#xff0c;可以看到&#xff0c;该部分的CRC7校验值得0x05,大多数情况…

二战架构师,拿下

前言 已经许久更新文章了&#xff0c;并不是因为我懒了&#xff0c;而是在备考系统架构师考试。个人感觉还是比较幸运的&#xff0c;低分飘过。现阶段任务也算完成了&#xff0c;记录一下感受。 什么是软考 软考&#xff0c;全称“计算机技术与软件专业技术资格&#xff08…

Agent如何帮助大模型“增强记忆”?

Agent如何帮助大模型“增强记忆”&#xff1f; 原创 格林 神州问学 2024年07月08日 17:50 日本 记忆反馈 >规划&#xff1f; 来源|神州问学 引言 去年6月份&#xff0c;Lilian发布了关于LLM驱动的Agent的结构和组件&#xff0c;其中包括规划、行动、工具还有记忆&#xff…

去除Win32 Tab Control控件每个选项卡上的深色对话框背景

一般情况下&#xff0c;我们是用不带边框的对话框来充当Tab Control的每个选项卡的内容的。 例如&#xff0c;主对话框IDD_TABBOX上有一个Tab Control&#xff0c;上面有两个选项卡&#xff0c;第一个选项卡用的是IDD_DIALOG1充当内容&#xff0c;第二个用的则是IDD_DIALOG2。I…

C++相关概念和易错语法(17)(适配器模式、仿函数)

1.stack和queue stack和queue的相关接口如下&#xff1a; stack queue 我们发现不管是stack还是queue&#xff0c;它们都有push和pop&#xff0c;不区分push_back和push_front&#xff0c;这是由它们的入栈特定顺序特性决定的&#xff0c;并且它们都没有迭代器&#xff0c;st…

【系统架构设计】计算机组成与体系结构(一)

计算机组成与体系结构 计算机系统组成计算机硬件组成控制器运算器主存储器辅助存储器输入设备输出设备 计算机系统结构的分类存储程序的概念Flynn分类 复杂指令集系统与精简指令集系统总线 存储器系统流水线 兜兜转转&#xff0c;最后还是回到了4大件&#xff0c;补基础&#x…

【力扣】数组中的第K个最大元素

一、题目描述 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入: [3,2,1,5,…

图片像素坐标转实际坐标的一种转换方案

原图 红色的点是我们标注的像素点&#xff0c;这些红色的点我们知道它的像素坐标&#xff0c;以及以右下角相机位置为原点的x y 实际坐标数值 通过转换&#xff0c;可以得到整个图片内部其余像素点的实际坐标&#xff0c; 这些红色的点是通过转换关系生成的&#xff0c;每隔一米…

python破解密码·筛查和选择

破解密码时可能遇到的几种情况 ① 已知密码字符&#xff0c;破排序 ② 已知密码位数&#xff0c;破字符 ③ 已知密码类型&#xff0c;破字位 ④ 已知部分密码&#xff0c;破未知 ⑤ 啥都不知道&#xff0c;盲破&#xff0c;玩完 ⑥ 已知位数、字符、类型、部分密码中的几个&am…

2024全网最全面及最新且最为详细的网络安全技巧五 之 SSRF 漏洞EXP技巧,典例分析以及 如何修复 (下册)———— 作者:LJS

五.SSRF 漏洞EXP技巧&#xff0c;典例分析以及 如何修复 (下册) 目录 五.SSRF 漏洞EXP技巧&#xff0c;典例分析以及 如何修复 (下册) 5.4gopher 协议初探 0x01 Gopher协议 0x02 协议访问学习 复现环境 centos7 kali 2018 发送http get请求 发送http post请求 5.5 SSRF…

☺初识c++(语法篇)☺

目录 一命名空间&#xff08;namespace&#xff09;&#xff1a; 二cout与cin简述&#xff1a; 三缺省参数&#xff1a; 四函数重载&#xff1a; 五引用&#xff1a; 六内联函数: 七c中的nullptr简述&#xff1a; 一命名空间&#xff08;namespace&#xff09;&#xff1…