后端:Spring、Spring Boot-实例化Bean依赖注入(DI)

news2024/11/5 9:02:30

文章目录

    • 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 +
                '}';
    }
}

在这里插入图片描述

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

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

相关文章

Android——横屏竖屏

系统配置变更的处理机制 为了避免横竖屏切换时重新加载界面的情况&#xff0c;Android设计了一中配置变更机制&#xff0c;在指定的环境配置发生变更之时&#xff0c;无需重启活动页面&#xff0c;只需执行特定的变更行为。该机制的视线过程分为两步&#xff1a; 修改 Androi…

ubuntu openmpi安装(超简单)

openmpi安装 apt update apt install openmpi-bin openmpi-common libopenmpi-dev安装到此完毕 测试一下&#xff0c;success !

基于DCT的数字水印算法

摘要 数字水印技术近年来得到了较大的发展&#xff0c;基于变换域的水印技术是目前研究的热点。数字水印是利用数字作品中普遍存在的冗余数据和随机性&#xff0c;把标识版权的水印信息嵌入到数字作品中&#xff0c;从而可以起到保护数字作品的版权或其完整性的一种技术。 一个…

【Linux指令】---获取进程的PID

获取进程的PID getpid()函数

李红《复变函数与积分变换》第五版课后习题答案PDF

《复变函数与积分变换(第五版)学习辅导与习题全解》是与《复变函数与积分变换(第五版)》(华中科技大学数学与统计学院)配套的学习辅导书&#xff0c; 全书共八章&#xff1a;复数与复变函数&#xff0c; 解析函数&#xff0c;复变函数的积分&#xff0c; 解析函数的级数表示&am…

Zypher Network:全栈式 Web3 游戏引擎,服务器抽象叙事的引领者

近期&#xff0c;《黑神话&#xff1a;悟空》的爆火不仅让 AAA 游戏重回焦点&#xff0c;也引发了玩家与开发者的热议。Web2 游戏的持续成功导致部分 Web3 玩家们的倒戈&#xff0c;对比之下 Web3 游戏存在生命周期短且商业模式难以明确的问题&#xff0c;尤其在当前加密市场环…

【Linux】利用 <信号量> 实现 <生产者-消费者模型-线程同步 >(思维导图&代码演示&思路解析)

前言 大家好吖&#xff0c;欢迎来到 YY 滴Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

「Mac畅玩鸿蒙与硬件20」鸿蒙UI组件篇10 - Canvas 组件自定义绘图

Canvas 组件在鸿蒙应用中用于绘制自定义图形,提供丰富的绘制功能和灵活的定制能力。通过 Canvas,可以创建矩形、圆形、路径、文本等基础图形,为鸿蒙应用增添个性化的视觉效果。本篇将介绍 Canvas 组件的基础操作,涵盖绘制矩形、圆形、路径和文本的实例。 关键词 Canvas 组件…

spark-on-k8s 介绍

spark-on-k8s 介绍 摘要 最近一段时间都在做与spark相关的项目&#xff0c;主要是与最近今年比较火的隐私计算相结合&#xff0c;主要是在机密计算领域使用spark做大数据分析、SQL等业务&#xff0c;从中也了解到了一些spark的知识&#xff0c;现在做一个简单的总结&#xff…

【运动的&足球】足球场地区域图像分割系统源码&数据集全套:改进yolo11-RFAConv

改进yolo11-ContextGuidedDown等200全套创新点大全&#xff1a;足球场地区域图像分割系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.10.28 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”展…

C语言 | Leetcode C语言题解之第525题连续数组

题目&#xff1a; 题解&#xff1a; struct HashTable {int key, val;UT_hash_handle hh; };int findMaxLength(int* nums, int numsSize) {int maxLength 0;struct HashTable* hashTable NULL;struct HashTable* tmp malloc(sizeof(struct HashTable));tmp->key 0, tm…

Java JUC(四) 自定义线程池实现与原理分析

目录 一. 阻塞队列 BlockingQue 二. 拒绝策略 RejectPolicy 三. 线程池 ThreadPool 四. 模拟运行 在 Java基础&#xff08;二&#xff09; 多线程编程 中&#xff0c;我们简单介绍了线程池 ThreadPoolExecutor 的核心概念与基本使用。在本文中&#xff0c;我们将基于前面学…

金华迪加 现场大屏互动系统 mobile.do.php 任意文件上传漏洞复现

0x01 产品简介 金华迪加现场大屏互动系统是一种集成了先进技术和创意设计的互动展示解决方案,旨在通过大屏幕和多种交互方式,为观众提供沉浸式的互动体验。该系统广泛应用于各类活动、展览、会议等场合,能够显著提升现场氛围和参与者的体验感。 0x02 漏洞概述 金华迪加 现…

2024年系统架构师---下午题目真题

1. 数据仓库架构风格的优缺点&#xff1a; 优点&#xff1a; 1&#xff09;数据统一保存在中央数据仓库&#xff0c;数据处理流程相对独立&#xff0c;支持交互式处理。 缺点&#xff1a; 1&#xff09;仓库风格不支持并行&#xff0c;效率低。 2&#xff09;仓库风格容错性和健…

JVM、JRE、JDK区别和联系

JVM(java virtual machine)&#xff1a;Java虚拟机主要包括类加载器、执行引擎、本地接口和运行时数据区&#xff0c;其中运行时数据区是JVM的主要部分。JVM的主要作用是将class文件中的二进制数据加载到运行时数据区的方法区&#xff0c;在堆区生成相应的java.lang.Class对象&…

Vue中ref、reactive、toRef、toRefs的区别

一、ref、reactive setup 函数中默认定义的变量并不是响应式的&#xff08;即数据变了以后页面不会跟着变&#xff09;&#xff0c;如果想让变量变为响应式的变量&#xff0c;需要使用 ref 和 reactive 函数修饰变量。 ref 函数可以把基本类型变量变为响应式引用reactive 函数…

Linux安装es和kibana

安装Elasticsearch 参考文档&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/targz.html#targz-enable-indices 基本步骤下载包&#xff0c;解压&#xff0c;官网提示&#xff1a; wget https://artifacts.elastic.co/downloads/elasticsearc…

spreadjs实现类似于企业微信的协同提示

核心代码 import * as GC from "grapecity-software/spread-sheets";function HighlightLayout(name:string){this.name name;this._eventNs ".HighlightLayout" name || "";this._sheetRangesInfo {} } HighlightLayout.prototype.bind f…

Linux云计算 |【第五阶段】PROJECT3-DAY1

主要内容&#xff1a; 跳板机&#xff08;堡垒机&#xff09;的概念、部署JumpeServer 一、跳板机&#xff08;堡垒机&#xff09;的概念 跳板机&#xff08;Jump Server 或 Bastion Host&#xff09;是一种网络安全设备或服务器&#xff0c;也称堡垒机&#xff0c;是一类可作…

PAT甲级-1133 Splitting A Linked List

题目 题目大意 给定一个链表的首节点地址和节点个数&#xff0c;以及一个数k。要求重新排列该链表&#xff0c;使其按<0 &#xff0c;> 0 && < k&#xff0c;>k 的顺序排序。但是不改变原有顺序&#xff0c;比如-4 -> -6 -> -2&#xff0c;不需要再…