后端:Spring、Spring Boot-实例化Bean依赖注入(DI)
文章目录
- 1. 实例化Bean
- 2. 使用FactoryBean
- 3. 依赖注入(DI)
- 3.1 @AutoWired 属性注入(查找顺序:先类型,后名字)
- 3.2 @AutoWired 在构造函数&参数上的使用
- 3.3 @Inject和@Resource 进行依赖注入
- 3.4 @Value 进行注入
1. 实例化Bean
默认使用无参构造函数,如果在这个Bean下定义了一个有参的构造方法(没有写无参构造方法),实例化时使用的是这个有参构造方法;如果有多个有参的构造方法(没有写无参构造方法),此时实例化时会报错,因为不知道使用哪个构造方法。
package com.lize.demo.dao;import com.lize.demo.TestBean;
import com.lize.demo.TestBean2;
import org.springframework.stereotype.Component;@Component("UserDao")
public class UserDao {private TestBean tb;private TestBean2 tb2;
// public UserDao(){
// System.out.println("构造函数");
// }public UserDao(TestBean tb){System.out.println("有参的构造函数"+tb);this.tb = tb;}public UserDao(TestBean tb,TestBean2 tb2){System.out.println("有参的构造函数"+tb+tb2);this.tb = tb;this.tb2 = tb2;}public void printUserDao(){System.out.println("UserDao");}}
package com.lize.demo;import com.lize.demo.dao.UserDao;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class DemoApplicationTests {@Autowiredprivate UserDao ud;@Testvoid contextLoads() {ud.printUserDao();}}
报错信息如下:

此时如果要实例化有参的Bean,可以使用注解@Bean的方式来进行,如下:
package com.lize.demo.dao;import com.lize.demo.TestBean;
import com.lize.demo.TestBean2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;public class UserDao {private TestBean tb;private TestBean2 tb2;public UserDao(TestBean tb){System.out.println("有参的构造函数"+tb);this.tb = tb;}public UserDao(TestBean tb,TestBean2 tb2){System.out.println("有参的构造函数"+tb+tb2);this.tb = tb;this.tb2 = tb2;}public void printUserDao(){System.out.println("UserDao");}}
package com.lize.demo.config;import com.lize.demo.TestBean;
import com.lize.demo.TestBean2;
import com.lize.demo.dao.UserDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;@Configuration
public class SpringConnfig {@Beanpublic UserDao getUserDao(TestBean tb,TestBean2 tb2){return new UserDao(tb,tb2);}
}
运行结果如下:

2. 使用FactoryBean
定义一个类,让其实现FactoryBean这个接口,并重写其下方法,如下:
package com.lize.demo.service;import com.lize.demo.TestBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Service;@Service("UserService")
public class UserService implements FactoryBean {@Overridepublic Object getObject() throws Exception {return new TestBean();}@Overridepublic Class<?> getObjectType() {return null;}
}
package com.lize.demo;import com.lize.demo.dao.UserDao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);System.out.println(context.getBean("UserService"));}}
此时的打印结果如下:

上述打印结果为TestBean,而不是UserService这个Bean。如果要获取UserService这个Bean,可以通过类型获取,如下:

还有一种做法就是在第一种的基础上,通过字符串获取Bean,字符串前面加上“&”符号,如下:

如果想通过类型获取TestBean这个Bean,可以在getObjectType方法下添加对应的类型信息,如下:


运行结果:

总结一下:
使用FactoryBean来实例化Bean。
- FactoryBean是一个接口;
- 需要有一个Bean,一旦这个Bean实现FactoryBean就成为了特殊的Bean;
- 需要实现两个方法
- getObject,当通过Bean实际名获取到的Bean就是getObject返回的对象(伪装);
- getObjectType,想通过获取对应的类型去获取这个伪装的Bean,就需要返回getObject返回的对象的类型;
- 可以自由控制Bean的构造方法来实例化Bean
3. 依赖注入(DI)
3.1 @AutoWired 属性注入(查找顺序:先类型,后名字)
使用这个注解,首先会通过类型去容器中查找是否有这个Bean,如果没有,再通过名字去查找是否有这个Bean。
直接在类上添加注解@Component定义Bean,名字为testBean3
package com.lize.demo;import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;@Component
//@Primary
public class TestBean3 {private String name;public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "TestBean3{" +"name='" + name + '\'' +'}';}
}
使用配置类定义Bean,名字为:TestBean31
package com.lize.demo.config;import com.lize.demo.TestBean3;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class SpringConnfig {@Beanpublic TestBean3 TestBean31(){return new TestBean3();}
}
上述定义了两个类型相同的Bean。
package com.lize.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class TestBean4 {@Autowiredprivate TestBean3 testBean3;@Overridepublic String toString() {return "TestBean4{" +"testBean3=" + testBean3 +'}';}
}
在TestBean4 中引入这个Bean,然后在单元测试中输出结果如下:
package com.lize.demo;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class DemoApplicationTests {@Autowiredprivate TestBean4 tb4;@Testvoid contextLoads() {System.out.println(tb4);}
}
运行结果如下:

可以看到,此时因为有两个Bean类型相同,因此采用名字去查找Bean,在TestBean4中使用的Bean名字为testBean3,因此输出的结果中的Bean为直接在类上添加注解@Component的那个Bean(name的值默认为空)。如果把TestBean4中的那个Bean的名字修改为TestBean31,那么此时的输出结果就是通过配置类定义的那个Bean了。
package com.lize.demo.config;import com.lize.demo.TestBean3;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class SpringConnfig {@Beanpublic TestBean3 TestBean31(){TestBean3 testBean3 = new TestBean3();testBean3.setName("TestBean31");return testBean3;}}
package com.lize.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class TestBean4 {@Autowiredprivate TestBean3 TestBean31;@Overridepublic String toString() {return "TestBean4{" +"testBean3=" + TestBean31 +'}';}
}

如果通过名字还是查找不到,比如把TestBean4中的引入那个Bean的名字修改为tb3,那么此时就会报错了。

此时可以在定义Bean的那个类上添加注解 @Primary,表示主要的。


另外一种解决方法就是在这个TestBean4引入的那个Bean下指明到底是哪个Bean(使用注解 @Qualifier),如下:

3.2 @AutoWired 在构造函数&参数上的使用
如果一个Bean定义了多个有参的构造函数,但是没有定义默认的构造函数(无参构造函数),此时在另外一个类中引入这个Bean,然后在单元测试中输出这个Bean,会报错,如下:
package com.lize.demo.dao;import com.lize.demo.TestBean;
import com.lize.demo.TestBean2;
import org.springframework.stereotype.Component;@Component("UserDao")
public class UserDao {private TestBean tb;private TestBean2 tb2;
// public UserDao(){
// System.out.println("构造函数");
// }public UserDao(TestBean tb){System.out.println("有参的构造函数"+tb);this.tb = tb;}public UserDao(TestBean tb,TestBean2 tb2){System.out.println("有参的构造函数"+tb+tb2);this.tb = tb;this.tb2 = tb2;}public void printUserDao(){System.out.println("UserDao");}}

如果此时想要正常输出,可以在对应的构造函数上面添加注解@AutoWired ,如下,此时正常输出。

TestBean、TestBean2如下形式:

如果想要为构造函数中的参数设置为不必须的,需要在参数上面设置 @Autowired(required = false),直接在构造函数上设置是不生效的,因此会报错(下面没有给出),如下:


此时打印结果为null。
另外,还可以写在单元测试的方法上面,如下:

Spring会自动调用@Autowired的方法进行自动注入,在没有调用set的方法的前提下,此时调用get的结果不为null,如下:
package com.lize.demo.dao;import com.lize.demo.TestBean;
import com.lize.demo.TestBean2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component("UserDao")
public class UserDao {private TestBean tb;private TestBean2 tb2;
// public UserDao(){
// System.out.println("构造函数");
// }@Autowiredpublic UserDao(@Autowired(required = false) TestBean tb){System.out.println("有参的构造函数"+tb);this.tb = tb;}@Autowiredpublic void setTb2(TestBean2 tb2){this.tb2 = tb2;}public TestBean2 getTb2(){return tb2;}public UserDao(TestBean tb,TestBean2 tb2){System.out.println("有参的构造函数"+tb+tb2);this.tb = tb;this.tb2 = tb2;}public void printUserDao(){System.out.println("UserDao");}}

3.3 @Inject和@Resource 进行依赖注入
@Resource优先根据名字进行查找,找不到再根据类型查找。
@inject不能设置required=false属性,另外还需要添加额外的依赖。
推荐使用构造函数进行注入,或者@Resource进行注入
3.4 @Value 进行注入
基本数据类型的注入
package com.lize.demo.entity;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class User {@Value("lize")private String name;@Value("19")private Integer age;@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
package com.lize.demo;import com.lize.demo.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class DemoApplicationTests {@Testvoid contextLoads(@Autowired User user) {System.out.println(user);}}

如果想通过从文件中的数据进行注入,如下,新建a.properties


在Spring Boot项目中,如果想获取配置文件application.properties中的数据,不需要使用@PropertySource指定路径文件,如下:


如果在数据文件获取不到对应数据,在Spring Boot项目中会报错(解决方法为在变量名后面加入“:”填写默认值),但是在Spring中会指定把值直接注入到对应变量。

复杂数据类型的注入,使用spel表达式的方式进行注入,如下:
package com.lize.demo.entity;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.Map;@Component
public class User {@Value("#{{'语文':'98'}}")private Map<String,String> score;@Value("#{'王者,原神'}")private List<String> like_games;@Overridepublic String toString() {return "User{" +"score=" + score +", like_games=" + like_games +'}';}
}

相关文章:
后端:Spring、Spring Boot-实例化Bean依赖注入(DI)
文章目录 1. 实例化Bean2. 使用FactoryBean3. 依赖注入(DI)3.1 AutoWired 属性注入(查找顺序:先类型,后名字)3.2 AutoWired 在构造函数&参数上的使用3.3 Inject和Resource 进行依赖注入3.4 Value 进行注入 1. 实例化Bean 默认使用无参构造函数&…...
C++ 数据结构 静态顺序表、动态顺序表。
静态顺序表(Static Array List)是一种线性数据结构,通常用数组实现。它具有固定的大小,并在编译时分配内存。以下是静态顺序表的一些基本概念和实现示例。 静态顺序表基本概念 固定大小:静态顺序表的大小在创建时定义…...
QML旋转选择器组件Tumbler
1. 介绍 Tumbler是一个用于创建旋转选择器的组件。它提供了一种直观的方式来让用户从一组选项中进行选择,类似于转盘式数字密码锁。网上找的类似网图如下: 在QML里,这种组件一共有两个版本,分别在QtQuick.Extras 1.4(旧)和QtQuic…...
在工作中常用到的 Linux 命令总结
引言 我之前找工作面试的时候。几乎每次面试几乎都会问到 Linux 常用命令,会问一些命令的应用场景。目的是考察我们是否在实际开发中经常用、用得熟练。今天我就来系统地总结一下开发过程中最常用的 Linux 命令,算是一个复习总结。 基本操作 文件管理…...
反射、枚举和lambda表达式
文章目录 一、反射1.1 什么是反射1.2 反射相关的类1.3 示例获取Class对象通过反射去创建对象调用带两个参数且私有的构造方法获取私有属性反射私有方法 二、枚举2.1 什么是枚举以及其优缺点2.2 如何使用枚举组织常量的基本方法枚举类的其他方法示例枚举能否通过反射拿到实例对象…...
Stable Diffusion Web UI 1.9.4常用插件扩展-WD14-tagger
Stable Diffusion Web UI 1.9.4 运行在 WSL 中的 Docker 容器中 tagger 插件的作用是,上传一张图片,反推这张图片可能的提示词。 使用场景就是,想要得到类似的图片内容时使用。 WD14-tagger 安装 Stable Diffusion WebUI WD14-tagger GitH…...
java 第19天 Lambda、jdk8.0新方法、Optional
一.Lambda表达式 前提是:参数是函数式接口才可以书写Lambda表达式 函数式接口条件: 1.接口 2.只有一个抽象方法 lambda表达式又称为匿名函数,允许匿名函数以参数的形式传入方法,简化代码 lambda表达式分为两部分()->{} …...
江协科技STM32学习- P31 I2C通信协议
🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝…...
6、liunx目录的功能
一、目录简介 Linux主要树结构目录包括:/、/root、/home、/usr、/bin、/tmp、/sbin、/proc、/boot 【Linux系统中常见目录功能如下】 / 根目录;/bin 存放必要的命令;(普通用户) /boot 存放内核以及启动所需的文件&…...
挑战Java面试题复习第5天,无人扶我青云志
挑战第 5 天 java反射List Set Map 区别Object 常用方法 java反射 定义: 运行时动态获取类信息和调用方法的特性。 应用场景: JDBC数据库连接。框架如Hibernate和Struts等。 实现方式: 通过四种方法获取Class对象: Class.fo…...
大规模语言模型:从理论到实践(1)
1、绪论 大规模语言模型(Large Language Models,LLM)是由包含数百亿以上参数的深度神经网络构建的语言模型,采用自监督学习方法通过大量无标注文本进行训练。自2018年以来,多个公司和研究机构相继发布了多种模型&#…...
C#如何锁定和解除鼠标及键盘BlockInput
在C#中,"BlockInput"通常指的是一个功能或方法,用于阻止或暂停用户输入一段时间。这在某些特定的应用场景下非常有用,比如在游戏中防止玩家连续快速点击导致游戏逻辑错误,或者在UI应用中防止用户在某个操作正在进行时进…...
Stable Diffusion 3.5发布:图像生成新纪元,多模态AI的突破!
在人工智能的图像生成领域,我们刚刚迎来了一位新的明星——Stable Diffusion 3.5。这是一款由多模态扩散Transformer(MMDiT)驱动的文本到图像模型,它在图像质量、字体处理、复杂提示理解以及资源效率方面都实现了显著提升。今天&a…...
MySQL超大分页怎么优化处理?limit 1000000,10 和 limit 10区别?覆盖索引、面试题
1. limit 100000,10 和 limit 10区别 LIMIT 100000, 10: 这个语句的意思是,从查询结果中跳过前100000条记录,然后返回接下来的10条记录。这通常用于分页查询中,当你需要跳过大量的记录以获取后续的记录时。例如,如果你…...
RabbitMQ 实现消息队列负载均衡
在现代应用程序中,消息队列是一种重要的架构模式,用于解耦服务、处理异步任务和实现负载均衡。其中,RabbitMQ是一个广泛使用的开源消息代理,提供了高可用性、可靠性和灵活性。本文将展示如何使用Python及其pika库来实现RabbitMQ&a…...
嵌入式linux中HTTP协议原理基本分析
第一:HTTP协议简介 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。 HTTP的发展是由蒂姆伯纳斯-李于1989年在欧洲核子研究组织(CERN)所发起。HTTP的标准制定由万维…...
thinkphp和vue基于Workerman搭建Websocket服务实现用户实时聊天,完整前后端源码demo及数据表sql
最近接了一个陪玩小程序,其中有一个实时聊天的项目,需要搭建Websocke服务,通过多方考虑选择了通过GatewayWorker框架(基于Workerman),将代码提取了出来,用到的框架封装到了vendor目录下,完整前后…...
浅谈射频应用
射频(Radio Frequency,缩写为RF)是一种高频交流变化电磁波的简称,其频率范围广泛,从几十千赫兹跨越至几百吉赫兹。射频技术在多个领域有着广泛的应用: 1、通信领域:射频技术是现代通信领域的重要…...
SAP(PP生产制造)拆解工单业务处理
1、BOM维护 要拆解的成品或半成品要和原成品、半成品BOM一致 2、创建拆解工单 CO01选择拆解工单的类型,以及填写拆解的物料和拆解工厂 维护工单组件 注意: 1、拆解入库组件的数量需要维护为负数 2、拆解工单投料组件数量维护为正数 3、拆解工单收发…...
《Python游戏编程入门》注-第4章2
《Python游戏编程入门》的“4.2.2 键盘事件”中介绍了通过键盘事件来监听键盘按键的方法。 1 键盘事件 玩家点击键盘中某个按键实际上包含了两个动作:点击按键和释放按键,也就是按键按下和松开。按键按下的对应的事件是KEYDOWN,按键松开对应…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...
QT开发技术【ffmpeg + QAudioOutput】音乐播放器
一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下,音视频内容犹如璀璨繁星,点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频,到在线课堂中知识渊博的专家授课,再到影视平台上扣人心弦的高清大片,音…...
