后端: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 {

    @Autowired
    private UserDao ud;

    @Test
    void 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 {
    @Bean
    public 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 {

    @Override
    public Object getObject() throws Exception {
        return new TestBean();
    }

    @Override
    public 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;
    }

    @Override
    public 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 {

    @Bean
    public 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 {

    @Autowired
    private TestBean3 testBean3;

    @Override
    public 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 {

    @Autowired
    private TestBean4 tb4;

    @Test
    void 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 {

    @Bean
    public 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 {

    @Autowired
    private TestBean3 TestBean31;

    @Override
    public 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("构造函数");
//    }

    @Autowired
    public UserDao(@Autowired(required = false) TestBean tb){
        System.out.println("有参的构造函数"+tb);
        this.tb = tb;
    }

    @Autowired
    public 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;

    @Override
    public 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 {

    @Test
    void 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;

    @Override
    public String toString() {
        return "User{" +
                "score=" + score +
                ", like_games=" + like_games +
                '}';
    }
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

qt QPicture详解

1、概述 QPicture类是Qt框架中的一个重要图形类&#xff0c;它主要用于记录和回放QPainter的绘图指令。这个类能够跨平台、无分辨率依赖地绘制图形&#xff0c;非常适合用于实现打印预览和图像操作等场景。QPicture可以将绘图操作序列化为一种独立于平台的格式&#xff0c;保存…

【计算机网络教程】课程 章节测试1 计算机网络概述

一. 单选题&#xff08;共16题&#xff09; 1 【单选题】以下关于TCP/IP参考模型缺点的描述中&#xff0c;错误的是&#xff08; &#xff09;。 A、在服务、接口与协议的区别上不很清楚 B、网络接口层本身并不是实际的一层 C、它不能区分数据链路和物理层 D、传输层对…

金融标准体系

目录 基本原则 标准体系结构图 标准明细表 金融标准体系下载地址 基本原则 需求引领、顶层设计。 坚持目标导向、问题导向、结果 导向有机统一&#xff0c;构建支撑适用、体系完善、科学合理的金融 标准体系。 全面系统、重点突出。 以金融业运用有效、保护有力、 管理高…

Linux练习作业

1.搭建dns服务器能够对自定义的正向或者反向域完成数据解析查询。 2.配置从DNS服务器&#xff0c;对主dns服务器进行数据备份 环境准备 主从服务器都需要进行的操作#关闭防火墙、SELinnux systemctl stop firewalld setenforce 0#软件安装 yum install bind -y实验一&#…

【STL_list 模拟】——打造属于自己的高效链表容器

一、list节点 ​ list是一个双向循环带头的链表&#xff0c;所以链表节点结构如下&#xff1a; template<class T>struct ListNode{T val;ListNode* next;ListNode* prve;ListNode(int x){val x;next prve this;}};二、list迭代器 2.1、list迭代器与vector迭代器区别…

《Qwen2-VL》论文精读【上】:发表于2024年10月 Qwen2-VL 迅速崛起 | 性能与GPT-4o和Claude3.5相当

1、论文地址Qwen2-VL: Enhancing Vision-Language Model’s Perception of the World at Any Resolution 2、Qwen2-VL的Github仓库地址 该论文发表于2024年4月&#xff0c;是Qwen2-VL的续作&#xff0c;截止2024年11月&#xff0c;引用数24 文章目录 1 论文摘要2 引言3 实验3.…

LiveQing视频点播流媒体RTMP推流服务功能-支持电子放大拉框放大直播视频拉框放大录像视频流拉框放大电子放大

LiveQing视频点播流媒体RTMP推流服务功能-支持电子放大拉框放大直播视频拉框放大录像视频流拉框放大电子放大 1、鉴权直播2、视频点播3、RTMP推流视频直播和点播流媒体服务 1、鉴权直播 云直播服务-》鉴权直播 -》播放 &#xff0c;左键单击可以拉取矩形框&#xff0c;放大选中…

Zypher Research:服务器抽象叙事,GameFi 赛道的下一个热点?

继链抽象、账户抽象的概念后&#xff0c;Zypher Network 进一步提出了服务器抽象的概念&#xff0c;并基于 zk 技术率先推出了应用于 Web3 游戏领域的服务器抽象方案。基于该方案&#xff0c;游戏开发者能够在完全去中心化的环境下创建、运行游戏&#xff0c;而不需要依赖传统的…

【SpringCloud详细教程】-01-一文了解微服务

精品专题&#xff1a; 01.《C语言从不挂科到高绩点》课程详细笔记 https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482 02. 《SpringBoot详细教程》课程详细笔记 https://blog.csdn.net/yueyehuguang/category_12789841.html?spm1001.20…

在使用 AMD GPU 的 PyTorch 中实现自动混合精度

Automatic mixed precision in PyTorch using AMD GPUs — ROCm Blogs 随着模型规模的增加&#xff0c;训练它们所需的时间和内存——以及因此而产生的成本——也在增加。因此&#xff0c;采取任何措施来减少训练时间和内存使用都是非常有益的。这就是自动混合精度&#xff08;…

基于布局的3D场景生成技术:SceneCraft

1. 概述 随着室内设计和虚拟现实技术的快速发展,快速生成高质量的3D室内场景成为行业需求的重要方向。SceneCraft是一种新型的3D场景生成技术,旨在根据用户提供的布局和文本描述,一键生成详细的室内3D场景。该技术不仅简化了设计流程,还大大提高了设计效率和用户体验。 2…

【Python爬虫实战】深入解析 Selenium:从元素定位到节点交互的完整自动化指南

#1024程序员节&#xff5c;征文# &#x1f308;个人主页&#xff1a;易辰君-CSDN博客 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html ​ 前言 Selenium 是进行网页自动化操作的强大工具&#xff0c;在测试、数据抓取、用户行…

数据库->联合查询

目录 一、联合查询 1.联合查询 2.多表联合查询时MYSQL内部是如何进⾏计算的 3.多表联合查询 3.1语法 3.2指定多个表&#xff0c;进行联合查询 3.3通过表与表中的链接条件过滤掉无效数据 3.4通过指定列查询&#xff0c;精简查询结果​编辑 3.5可以通过给表起别名的方式&…

k8s知识点总结

docker 名称空间 分类 Docker中的名称空间用于提供进程隔离&#xff0c;确保容器之间的资源相互独立。主要分类包括&#xff1a; PID Namespace&#xff1a;进程ID隔离&#xff0c;使每个容器有自己的进程树&#xff0c;容器内的进程不会干扰其他容器或主机上的进程。 NET Nam…

C++11(1)——右值引用、统一初始化、C++发展史

一、C的发展史 1.C的产生 C的起源可以追溯到1979年&#xff0c;当时本贾尼&#xff08;C创始人&#xff09;在贝尔实验室从事计算机科学与软件工程的研究工作。面对项目中复杂的软件开发任务&#xff0c;特别是模拟和操作系统的开发工作&#xff0c;他感受到了现有语言&#…

计算机毕业设计Spark+大模型知识图谱中药推荐系统 中药数据分析可视化大屏 中药爬虫 机器学习 中药预测系统 中药情感分析 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

javascript-Web APLs (三)

事件流 指的是事件完整执行过程中的流动路 说明&#xff1a;假设页面里有个div&#xff0c;当触发事件时&#xff0c;会经历两个阶段&#xff0c;分别是捕获阶段、冒泡阶段 简单来说&#xff1a;捕获阶段是 从父到子 冒泡阶段是从子到父 实际工作都是使用事件冒泡为主 事件…

11.Three.js使用indexeddb前端缓存模型优化前端加载效率

11.Three.js使用indexeddb前端缓存模型优化前端加载效率 1.简述 在使用Three.js做数字孪生应用场景时&#xff0c;我们常常需要用到大量模型或数据。在访问我们的数字孪生应用时&#xff0c;每次刷新都需要从web端进行请求大量的模型数据或其他渲染数据等等&#xff0c;会极大…

keepalive+mysql8双主

1.概述 利用keepalived实现Mysql数据库的高可用&#xff0c;KeepalivedMysql双主来实现MYSQL-HA&#xff0c;我们必须保证两台Mysql数据库的数据完全一致&#xff0c;实现方法是两台Mysql互为主从关系&#xff0c;通过keepalived配置VIP&#xff0c;实现当其中的一台Mysql数据库…

C++ 实现俄罗斯方块游戏

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…