当前位置: 首页 > news >正文

后端: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 属性注入(查找顺序&#xff1a;先类型&#xff0c;后名字)3.2 AutoWired 在构造函数&参数上的使用3.3 Inject和Resource 进行依赖注入3.4 Value 进行注入 1. 实例化Bean 默认使用无参构造函数&…...

C++ 数据结构 静态顺序表、动态顺序表。

静态顺序表&#xff08;Static Array List&#xff09;是一种线性数据结构&#xff0c;通常用数组实现。它具有固定的大小&#xff0c;并在编译时分配内存。以下是静态顺序表的一些基本概念和实现示例。 静态顺序表基本概念 固定大小&#xff1a;静态顺序表的大小在创建时定义…...

QML旋转选择器组件Tumbler

1. 介绍 Tumbler是一个用于创建旋转选择器的组件。它提供了一种直观的方式来让用户从一组选项中进行选择&#xff0c;类似于转盘式数字密码锁。网上找的类似网图如下&#xff1a; 在QML里&#xff0c;这种组件一共有两个版本&#xff0c;分别在QtQuick.Extras 1.4(旧)和QtQuic…...

在工作中常用到的 Linux 命令总结

引言 我之前找工作面试的时候。几乎每次面试几乎都会问到 Linux 常用命令&#xff0c;会问一些命令的应用场景。目的是考察我们是否在实际开发中经常用、用得熟练。今天我就来系统地总结一下开发过程中最常用的 Linux 命令&#xff0c;算是一个复习总结。 基本操作 文件管理…...

反射、枚举和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 插件的作用是&#xff0c;上传一张图片&#xff0c;反推这张图片可能的提示词。 使用场景就是&#xff0c;想要得到类似的图片内容时使用。 WD14-tagger 安装 Stable Diffusion WebUI WD14-tagger GitH…...

java 第19天 Lambda、jdk8.0新方法、Optional

一.Lambda表达式 前提是&#xff1a;参数是函数式接口才可以书写Lambda表达式 函数式接口条件&#xff1a; 1.接口 2.只有一个抽象方法 lambda表达式又称为匿名函数&#xff0c;允许匿名函数以参数的形式传入方法&#xff0c;简化代码 lambda表达式分为两部分()->{} …...

江协科技STM32学习- P31 I2C通信协议

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…...

6、liunx目录的功能

一、目录简介 Linux主要树结构目录包括&#xff1a;/、/root、/home、/usr、/bin、/tmp、/sbin、/proc、/boot 【Linux系统中常见目录功能如下】 / 根目录&#xff1b;/bin 存放必要的命令&#xff1b;&#xff08;普通用户&#xff09; /boot 存放内核以及启动所需的文件&…...

挑战Java面试题复习第5天,无人扶我青云志

挑战第 5 天 java反射List Set Map 区别Object 常用方法 java反射 定义&#xff1a; 运行时动态获取类信息和调用方法的特性。 应用场景&#xff1a; JDBC数据库连接。框架如Hibernate和Struts等。 实现方式&#xff1a; 通过四种方法获取Class对象&#xff1a; Class.fo…...

大规模语言模型:从理论到实践(1)

1、绪论 大规模语言模型&#xff08;Large Language Models&#xff0c;LLM&#xff09;是由包含数百亿以上参数的深度神经网络构建的语言模型&#xff0c;采用自监督学习方法通过大量无标注文本进行训练。自2018年以来&#xff0c;多个公司和研究机构相继发布了多种模型&#…...

C#如何锁定和解除鼠标及键盘BlockInput

在C#中&#xff0c;"BlockInput"通常指的是一个功能或方法&#xff0c;用于阻止或暂停用户输入一段时间。这在某些特定的应用场景下非常有用&#xff0c;比如在游戏中防止玩家连续快速点击导致游戏逻辑错误&#xff0c;或者在UI应用中防止用户在某个操作正在进行时进…...

Stable Diffusion 3.5发布:图像生成新纪元,多模态AI的突破!

在人工智能的图像生成领域&#xff0c;我们刚刚迎来了一位新的明星——Stable Diffusion 3.5。这是一款由多模态扩散Transformer&#xff08;MMDiT&#xff09;驱动的文本到图像模型&#xff0c;它在图像质量、字体处理、复杂提示理解以及资源效率方面都实现了显著提升。今天&a…...

MySQL超大分页怎么优化处理?limit 1000000,10 和 limit 10区别?覆盖索引、面试题

1. limit 100000,10 和 limit 10区别 LIMIT 100000, 10&#xff1a; 这个语句的意思是&#xff0c;从查询结果中跳过前100000条记录&#xff0c;然后返回接下来的10条记录。这通常用于分页查询中&#xff0c;当你需要跳过大量的记录以获取后续的记录时。例如&#xff0c;如果你…...

RabbitMQ 实现消息队列负载均衡

在现代应用程序中&#xff0c;消息队列是一种重要的架构模式&#xff0c;用于解耦服务、处理异步任务和实现负载均衡。其中&#xff0c;RabbitMQ是一个广泛使用的开源消息代理&#xff0c;提供了高可用性、可靠性和灵活性。本文将展示如何使用Python及其pika库来实现RabbitMQ&a…...

嵌入式linux中HTTP协议原理基本分析

第一:HTTP协议简介 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。 HTTP的发展是由蒂姆伯纳斯-李于1989年在欧洲核子研究组织(CERN)所发起。HTTP的标准制定由万维…...

thinkphp和vue基于Workerman搭建Websocket服务实现用户实时聊天,完整前后端源码demo及数据表sql

最近接了一个陪玩小程序&#xff0c;其中有一个实时聊天的项目&#xff0c;需要搭建Websocke服务&#xff0c;通过多方考虑选择了通过GatewayWorker框架&#xff08;基于Workerman&#xff09;,将代码提取了出来&#xff0c;用到的框架封装到了vendor目录下&#xff0c;完整前后…...

浅谈射频应用

射频&#xff08;Radio Frequency&#xff0c;缩写为RF&#xff09;是一种高频交流变化电磁波的简称&#xff0c;其频率范围广泛&#xff0c;从几十千赫兹跨越至几百吉赫兹。射频技术在多个领域有着广泛的应用&#xff1a; 1、通信领域&#xff1a;射频技术是现代通信领域的重要…...

SAP(PP生产制造)拆解工单业务处理

1、BOM维护 要拆解的成品或半成品要和原成品、半成品BOM一致 2、创建拆解工单 CO01选择拆解工单的类型&#xff0c;以及填写拆解的物料和拆解工厂 维护工单组件 注意&#xff1a; 1、拆解入库组件的数量需要维护为负数 2、拆解工单投料组件数量维护为正数 3、拆解工单收发…...

《Python游戏编程入门》注-第4章2

《Python游戏编程入门》的“4.2.2 键盘事件”中介绍了通过键盘事件来监听键盘按键的方法。 1 键盘事件 玩家点击键盘中某个按键实际上包含了两个动作&#xff1a;点击按键和释放按键&#xff0c;也就是按键按下和松开。按键按下的对应的事件是KEYDOWN&#xff0c;按键松开对应…...

【HarmonyOS 5】拍摄美化开发实践介绍以及详细案例

以下是 HarmonyOS 5 拍摄美化功能的简洁介绍&#xff0c;整合核心能力与技术亮点&#xff1a; 一、AI 影像创新 ‌AI 魔法移图‌ 系统级图像分层技术实现人物/物体自由拖拽、缩放与复制&#xff0c;突破传统构图限制。自动分离主体与背景&#xff0c;一键生成错位创意照&…...

从 ClickHouse、Druid、Kylin 到 Doris:网易云音乐 PB 级实时分析平台降本增效

网易云音乐基于 Apache Doris 替换了早期架构中 Kylin、Druid、Clickhouse、Elasticsearch、HBase 等引擎&#xff0c;统一了实时分析架构&#xff0c;并广泛应用于广告实时数仓、日志平台和会员报表分析等典型场景中&#xff0c;带来导入性能提升 3&#xff5e;30 倍&#xff…...

pgsql batch insert optimization (reWriteBatchedInserts )

reWriteBatchedInserts 是 PostgreSQL JDBC 驱动 提供的一个优化选项&#xff0c;它可以 重写批量插入语句&#xff0c;从而提高插入性能。 作用 当 reWriteBatchedInsertstrue 时&#xff0c;PostgreSQL JDBC 驱动会将 多个单独的 INSERT 语句 转换为 一个多行 INSERT 语句&a…...

【第七篇】 SpringBoot项目的热部署

简介 本文介绍了热部署&#xff08;Hot Deployment&#xff09;的概念、使用场景及在IDEA中的配置方法。热部署可在不重启应用的情况下动态更新代码&#xff0c;提升开发效率&#xff0c;适用于调试、微服务架构和自动化测试等场景。文章详细说明了热部署的实现步骤&#xff08…...

mac版excel如何制作时长版环形图

设置辅助列 创建簇状柱形图 将辅助列绘制在次坐标轴 工作时长在主坐标轴&#xff0c;右键分别更改图表类型为圆环。 辅助列圆环全部为灰色&#xff0c;边框为白色 辅助列设置透明度100% 设置辅助列和工作时长列同样的圆环大小 可得 核心&#xff1a;只要辅助列边框不透明…...

K8S认证|CKS题库+答案| 7. Dockerfile 检测

目录 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、修改 Dockerfile 3&#xff09;、 修改 deployment.yaml 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 您必须在以…...

嵌入式学习--江协stm32day5

USART 1. 引脚与接口层 异步引脚&#xff1a; TX&#xff1a;发送数据输出&#xff1b;RX&#xff1a;接收数据输入&#xff1b;SW_RX&#xff1a;单线半双工模式的接收引脚&#xff08;替代 RX&#xff09;。 同步引脚&#xff1a;SCLK&#xff1a;同步模式下的时钟输出&…...

Mysql 插入中文乱码

session范围 查看数据库编码&#xff1a; show variables like %char%; # MySQL 5.7 字符集强制配置 # 修复 character_set_databaselatin1 等问题 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci init_connect SET NAMES utf8mb4[client] d…...

Nodejs工程化实践:构建高性能前后端交互系统

一、工程架构设计 1.1 现代化项目初始化 采用多包管理架构&#xff1a; mkdir content-platform && cd content-platform npm init -y npx lerna init mkdir -p {packages/client,packages/server,packages/shared} 关键模块划分&#xff1a; client/: 基于Next.js…...

一键更新依赖全指南:Flutter、Node.js、Kotlin、Java、Go、Python 等主流语言全覆盖

在现代软件开发中&#xff0c;依赖项扮演着至关重要的角色。保持依赖的最新状态不仅可以获得新特性和性能优化&#xff0c;还能修复已知安全漏洞。但在不同语言和框架中&#xff0c;依赖管理的方式差异很大。本篇文章将系统性讲解如何在各主流语言中实现“一键更新依赖”。 &am…...