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

【Java EE】Spring IOCDI

Spring IOC & DI

文章目录

  • Spring IOC & DI
    • 一、Spring是什么?
    • 二、IOC(控制反转)
      • 2.1 通俗理解
      • 2.2 造汽车的例子理解IOC
      • 2.3 IOC详解
        • 1. 获取Bean
        • 2. 方法注解——@Bean
          • 1. 应用场景:
          • 2. 应用方法:
          • 3. 注意要点:
      • 特别注意:
    • 四、DI
      • 4.1 属性注入
        • 使用方法
      • 4.2 构造方法注入
        • 使用方法
      • 4.3 在setter方法注入
        • 使用方法
      • 4.4三种注⼊优缺点分析
      • 4.5 @Autowired出现多个同类型Bean的情况
        • 原因:
        • 解决方法:
          • 1. 使用 `@Primary` 指定默认匹配的项目
          • 2. 使用`autowireCandidate = false`去除默认匹配
          • 3. 使用 `@Resource(name="**")`对于特定名称的Bean进行注入
      • 4.6 @Autowired和@Rescource的区别

一、Spring是什么?

Spring是一个开发的框架,包含了很多的依赖,比如Spring MVC, Spring Boot等,这些让我们开发变得容易,可以说,Spring是一个包含很多工具方法的容器。

二、IOC(控制反转)

2.1 通俗理解

Inversio of Control ,也就是说,Spring是一个 “控制反转” 的容器。

控制反转就是让一个事物的控制权交由其他人。

2.2 造汽车的例子理解IOC

造汽车的流程:

在这里插入图片描述

代码:
汽车类:

package com.example.springioc.v1;public class Car {// 汽车依赖于框架private Frame frame;public Car() {frame = new Frame();System.out.println("汽车安装框架中...");}
}

框架类:

package com.example.springioc.v1;public class Frame {// 框架依赖于底盘private Bottom bottom;public Frame() {bottom = new Bottom();System.out.println("框架安装底盘中...");}
}

底盘类:

package com.example.springioc.v1;import jdk.jfr.Frequency;public class Bottom {// 底盘依赖于轮胎private Tire tire;// 有了尺寸的需求,需要进行传参public Bottom(int size) {tire = new Tire(size);System.out.println("底盘安装轮胎中...");}
}

轮胎类:

package com.example.springioc.v1;public class Tire {public Tire() {System.out.println("打造默认尺寸轮胎中...");}
}

运行结果:

在这里插入图片描述

这种代码架构,每个类的控制权都在调用他的那一方中,调用的一方创造了怎样的他,那他就是怎样的。

如果想要更换任意尺寸的轮胎,那就需要传递一个size参数,此时要依次对于代码做修改。

首先是轮胎类,需要增加 size 属性,但是这样最上层的 Car 类并不能够选择自己想要的尺寸,仍然需要对于控制着 Tire 的Bottom进行添加参数以便Frame能够添加参数,这样依赖,Frame也得添加size参数,Car 也需要。

最终代码(对于每一级都添加了size参数):

汽车类:

package com.example.springioc.v1;public class Car {// 汽车依赖于框架private Frame frame;// 对于汽车类添加了size参数构造public Car(int size) {frame = new Frame(size);System.out.println("汽车安装框架中...");}
}

框架类:

package com.example.springioc.v1;public class Frame {// 框架依赖于底盘private Bottom bottom;public Frame(int size) {bottom = new Bottom(size);System.out.println("框架安装底盘中...");}
}

底盘类:

package com.example.springioc.v1;import jdk.jfr.Frequency;public class Bottom {// 底盘依赖于轮胎private Tire tire;public Bottom(int size) {tire = new Tire(size);System.out.println("底盘安装轮胎中...");}
}

轮胎类:

package com.example.springioc.v1;public class Tire {// 轮胎的大小private Integer size;public Tire() {System.out.println("打造默认尺寸轮胎中...");}public Tire(int size) {System.out.println("打造"+size+"号的轮胎中...");}
}

显而易见,这样的代码架构维护起来非常臃肿
每一下级的控制权都由上一级保管,如果对于下一级的需求发生了变化,那么这就需要改动所有的类。(比如:如果现在用户需要对于轮胎的轮毂进行制定,那就还需要给Tire的构造函数增添一个 style 属性,如果还有颜色等的需求,那就还得一直加;只加Tire一个类的还好,因为每一上级都直间或者间接依赖于这个Tire,每一个类都需要进行修改,耦合度非常高。)

所以就需要 “控制反转” 思想,将整个控制反转:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

修改后的代码:

package com.example.springioc.v2;import com.example.springioc.v1.Frame;public class Main {static class Tire {int size;public Tire(int size) {this.size = size;System.out.println("打造"+size+"号轮胎...");}}static class Bottom{Tire tire;public Bottom(Tire tire) {this.tire = tire;System.out.println("打造底盘...");}}static class Framework {Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;System.out.println("打造框架...");}}static class Car {Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("打造汽车...");}}public static void main(String[] args) {Tire tire = new Tire(1);Bottom bottom = new Bottom(tire);Framework framework = new Framework(bottom);Car car = new Car(framework);}
}

这样一来,如果用户对于轮胎有新的需求,那也只需要修改轮胎这一个类,完成了整个代码的解耦。

也就是说,我们将控制权转让给了Tire自己,Tire的上级类不再享有控制权,传来什么Tire,就用什么。

2.3 IOC详解

控制反转之后,对象进入Spring容器就会变成Bean,也就是说,Spring中的对象都叫做Bean。

1. 获取Bean
  1. 注册Bean:使用五大注解,让Spring Boot能够发现@Bean
  2. 主要方法:使用 context 的 getBean() 进行获取
  3. 得到的Bean就相当于从Spring Boot中取到了这个对象

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. 方法注解——@Bean
1. 应用场景:
  1. 当对于外部类的方法,无法通过修改源码进行注册Bean,所以可以使用Spring的@Import注解来导入一个配置类,在这个配置类中你可以使用@Bean注解来声明这个外部类作为一个Bean,并对其进行配置。

  2. 如果一个类中需要多个实例,可以使用@Bean对于实例进行别名命名(value和name),以示区分。

2. 应用方法:
		/*** 使用@Bean的演示*/// 使用类,获得整个类的BeanUser bean1 = context.getBean(User.class);System.out.println(bean1);// li4是使用name属性定的别名User bean2 = (User) context.getBean("li4");System.out.println(bean2);// user3是方法的名字User bean3 = (User) context.getBean("user3");System.out.println(bean3);
3. 注意要点:
  1. @Bean是方法级的注解
  2. 需要配合类注解进行使用
  3. 使用value和name属性可以命名别名
  4. Bean的名字就是方法的名字
  5. autowireCandidate 可以消除:当有多个能够匹配的实例的时候,排除这个实例

特别注意:

@ComponentScan 可以定义Spring的扫描路径。

使用方法:

@ComponentScan({"com.example.springioc.bean_test"})

直接在()中使用{}定义路径。

四、DI

DI就是依赖注入。

4.1 属性注入

使用 @Autowired 注入。

使用方法
package com.example.springioc.di_test.controller;import com.example.springioc.di_test.service.TireSeervice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class TireController {@AutowiredTireSeervice tireSeervice;public void doTire() {System.out.println("成功调用轮胎控制器...");tireSeervice.doTire();}
}

使用 @Autowired 将service属性注入到控制器中。

package com.example.springioc.di_test.service;import com.example.springioc.di_test.model.Tire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class TireService {@AutowiredTire tire;public void doTire() {tire.setSize(12);tire.setColor("红");System.out.println("制作"+tire.getSize()+"号"+tire.getColor()+"色的轮胎");}
}

同时在服务类中将需要的轮胎对象注入。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.2 构造方法注入

将构造方法使用 @Autowired 注入。

使用方法
package com.example.springioc.di_test2.service;import com.example.springioc.di_test2.model.Tire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class TireService {Tire tire;@Autowired //构造函数上注入public TireService(Tire tire) {this.tire = tire;tire.setSize(12);tire.setColor("红");}public void doTire() {System.out.println("制作"+tire.getSize()+"号"+tire.getColor()+"色的轮胎");}}

在服务类的构造方法中使用@Autowired 中注入。

package com.example.springioc.di_test2.controller;import com.example.springioc.di_test2.service.TireService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class TireController {TireService tireService;@Autowired //构造函数上注入public TireController(TireService tireService) {this.tireService = tireService;}public void doTire() {System.out.println("成功调用轮胎控制器...");tireService.doTire();}}

在控制类的构造方法使用@Autowired 中注入。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.3 在setter方法注入

将构造方法使用 @Autowired 注入。

使用方法
package com.example.springioc.di_test3.service;import com.example.springioc.di_test3.model.Tire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class TireService {Tire tire;@Autowired //set方法上注入public void setTire(Tire tire) {this.tire = tire;tire.setSize(1);tire.setColor("green");}public void doTire() {System.out.println("制作"+tire.getSize()+"号"+tire.getColor()+"色的轮胎");}}

在服务类的setter方法中使用@Autowired 中注入。

package com.example.springioc.di_test3.controller;import com.example.springioc.di_test3.model.Tire;
import com.example.springioc.di_test3.service.TireService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class TireController {private TireService tireService;@Autowired //set方法上注入public void setTireService(TireService tireService) {this.tireService = tireService;}public void doTire() {System.out.println("成功调用轮胎控制器...");tireService.doTire();}}

在控制类的setter方法使用@Autowired 中注入。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.4三种注⼊优缺点分析

  1. 属性注⼊
    ◦ 优点: 简洁,使⽤⽅便;
    ◦ 缺点:
    ▪ 只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指
    针异常)
    ▪ 不能注⼊⼀个Final修饰的属性

  2. 构造函数注⼊(Spring 4.X推荐)
    ◦ 优点:
    ▪ 可以注⼊final修饰的属性
    ▪ 注⼊的对象不会被修改
    ▪ 依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法
    是在类加载阶段就会执⾏的⽅法.
    ▪ 通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的
    ◦ 缺点:
    ▪ 注⼊多个对象时, 代码会⽐较繁琐

  3. Setter注⼊(Spring 3.X推荐)
    ◦ 优点: ⽅便在类实例之后, 重新对该对象进⾏配置或者注⼊
    ◦ 缺点:
    ▪ 不能注⼊⼀个Final修饰的属性
    ▪ 注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤, 就有被修改的⻛险

4.5 @Autowired出现多个同类型Bean的情况

会发生报错:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

控制器类:

package com.example.springioc.autowired_test;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class TestController {@Autowired// 有两个String类型的BeanString name;public void sayHi() {System.out.println(name);}
}

组件类:

package com.example.springioc.autowired_test;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;@Component
public class BeanConfig {@Beanpublic String test1() {return new String("zhang3");}@Beanpublic String test2() {return new String("li4");}
}

可以看出组件中有两个String类型的Bean。

原因:

@Autowired不知道选择哪个Bean进行注入,发生了冲突,需要解决这个冲突。

解决方法:
1. 使用 @Primary 指定默认匹配的项目
2. 使用autowireCandidate = false去除默认匹配
3. 使用 @Resource(name="**")对于特定名称的Bean进行注入

在这里插入图片描述

在这里插入图片描述

4.6 @Autowired和@Rescource的区别

  1. @Autowired 是spring提供的注解,@Rescource是Java EE提供的注解

  2. @Autowired按照默认规则进行注入,但是@Rescource根据名称注入,有更多的选项。

    默认规则:
    在这里插入图片描述

  3. @Qualifer 优先级高于@Autowired

  4. @Autowired执行流程

    按照类型查找,如果只查到一个,就直接注入
    如果没有查到,报错
    如果查找到了多个,根据名称查找,查找到了,注入
    没有查找到,抛异常

  5. @Qualifier
    按照名称和类型去查

  6. @Qualifier +@Autowired
    直接按照类型+Qualifier的名称去查如果@Autowired对应的类型,只有一个,但是名称和@Qualifier名称不一样,注入也是失败的

相关文章:

【Java EE】Spring IOCDI

Spring IOC & DI 文章目录 Spring IOC & DI一、Spring是什么?二、IOC(控制反转)2.1 通俗理解2.2 造汽车的例子理解IOC2.3 IOC详解1. 获取Bean2. 方法注解——Bean1. 应用场景:2. 应用方法:3. 注意要点: 特别注意: 四、DI4…...

【FreeRTOS】同步互斥与通信 有缺陷的同步示例

目录 1 同步互斥与通信1.1 同步互斥与通信概述1.2 同步与互斥的概念1.3 同步的例子:有缺陷1.4 freertos.c源码3. 互斥的例子:有缺陷4. 通信的例子:有缺陷5. FreeRTOS的解决方案 1 同步互斥与通信 1.1 同步互斥与通信概述 参考《FreeRTOS入门…...

Lambda表达式讲解

简介: Lambda表达式的使用场景非常广泛,主要包括函数式编程、集合操作、排序、线程编程、GUI事件处理、数据处理、Web开发等。 函数式编程:Lambda表达式是函数式编程的重要特性,可以用于替代传统的匿名内部类,简化代码,提高可读性。 集合操作:Lambda表达式可以与集合…...

深入了解Linux中的dnsmasq:配置与优化指南

目录 安装dnsmasqUbuntu/DebianCentOS/RHELFedora 配置dnsmasq基本配置高级配置 启动和测试dnsmasq优化dnsmasq性能优化安全性优化 常见问题与故障排除无法解析域名DHCP分配失败 在Linux系统中, dnsmasq 是一个轻量级的网络服务,主要用于提供DNS缓存和D…...

【React】Ant Design -- Table分页功能实现

实现步骤 为Table组件指定pagination属性来展示分页效果在分页切换事件中获取到筛选表单中选中的数据使用当前页数据修改params参数依赖引起接口重新调用获取最新数据 const pageChange (page) > {// 拿到当前页参数 修改params 引起接口更新setParams({...params,page})…...

400G SR4和800G SR8光模块在AI集群中的应用

人工智能(AI)技术的快速发展下,AI集群的计算能力和数据传输需求不断提升。为了满足这一需求,光模块技术也在不断进步。高速率光模块作为新一代高速光通信解决方案,正在逐步应用于AI集群中,为其提供更高效、…...

ARM功耗管理软件之DVFSAVS

安全之安全(security)博客目录导读 思考:功耗管理软件栈及示例?WFI&WFE?时钟&电源树?DVFS&AVS? 目录 一、ARM功耗管理软件之DVFS 二、ARM功耗管理软件之AVS 一、ARM功耗管理软件之DVFS 有一个实现特定…...

【堆 优先队列】23. 合并 K 个升序链表

本文涉及知识点 堆 优先队列 LeetCode23. 合并 K 个升序链表 给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。 示例 1: 输入:lists [[1,4,5],[1,3,4],[2,6]] 输出&#…...

云桌面运维工程师

一 深信服驻场工程师 1 深信服AC、AF、AD、NGAF、WOC Atrust、WAF项目实施经验者优先考虑。 负责云桌面POC测试 部署和配置:设置云桌面基础设施,包括虚拟化平台、云桌面管理软件和相关组件。确保正确配置网络、存储和安全设置。 用户体验&#xff1…...

AGI 之 【Hugging Face】 的【Transformer】的 [ Transformer 架构 ] / [ 编码器 ]的简单整理

AGI 之 【Hugging Face】 的【Transformer】的 [ Transformer 架构 ] / [ 编码器 ]的简单整理 目录 AGI 之 【Hugging Face】 的【Transformer】的 [ Transformer 架构 ] / [ 编码器 ]的简单整理 一、简单介绍 二、Transformer 三、Transformer架构 四、编码器 1、自注意…...

【在大模型RAG系统中应用知识图谱】

【引子】 关于大模型及其应用方面的文章层出不穷,聚焦于自己面对的问题,有针对性的阅读会有很多的启发,本文源自Whyhow.ai 上的一些文字和示例。对于在大模型应用过程中如何使用知识图谱比较有参考价值,特汇总分享给大家。 在基于…...

第二十条:与抽象类相比,优先选择接口

要定义多种实现的类型:JAVA有两种机制:接口和抽象类。这两种机制都支持为某些实例方法提供实现,但二者有个重要的区别:要实现由抽象类定义的类型,这个类必须是抽象类的子类。因为Java只允许单继承,对抽象类…...

20240705

Nacos Service Discovery 通过nacos实现的服务发现平台 Spring Cloud Alibaba Sentinel 提供 Sentinel 自动接入和配置支持,提供 Spring Web/WebFlux、Feign、RestTemplate、注解等适配 Spring Cloud Alibaba Sentinel DataSource 提供 Sentinel 动态数据源接入支…...

【2023ICPC网络赛I 】E. Magical Pair

当时在做洛谷U389682 最大公约数合并的时候我就想到把每个质因子分解出来然后跑高维前缀和,但是那一道题不是用这个方法,所有我也一直在思考这种做法是不是真的有用。因为昨天通过2024上海大学生程序设计竞赛I-六元组计数这道题我了解到了不少关于原根的…...

Kafka-服务端-网络层-源码流程

整体架构如下所示: responseQueue不在RequestChannel中,在Processor中,每个Processor内部有一个responseQueue 客户端发送的请求被Acceptor转发给Processor处理处理器将请求放到RequestChannel的requestQueue中KafkaRequestHandler取出reque…...

百日筑基第十一天-看看SpringBoot

百日筑基第十一天-看看SpringBoot 创建项目 Spring 官方提供了 Spring Initializr 的方式来创建 Spring Boot 项目。网址如下: https://start.spring.io/ 打开后的界面如下: 可以将 Spring Initializr 看作是 Spring Boot 项目的初始化向导&#xff…...

Generative Modeling by Estimating Gradients of the Data Distribution

Generative Modeling by Estimating Gradients of the Data Distribution 本文介绍宋飏提出的带噪声扰动的基于得分的生成模型。首先介绍基本的基于得分的生成模型的训练方法(得分匹配)和采样方法(朗之万动力学)。然后基于流形假…...

vector与list的简单介绍

1. 标准库中的vector类的介绍: vector是表示大小可以变化的数组的序列容器。 就像数组一样,vector对其元素使用连续的存储位置,这意味着也可以使用指向其元素的常规指针上的偏移量来访问其元素,并且与数组中的元素一样高效。但与数…...

四种线程池的使用,优缺点分析

池化思想:线程池、字符串常量池、数据库连接池 提高资源的利用率 下面是手动创建线程和执行任务过程,可见挺麻烦的,而且线程利用率不高。 手动创建线程对象执行任务执行完毕,释放线程对象 线程池的优点: 提高线程的…...

什么是 BEM 规范

BEM(Block, Element, Modifier)是一种 CSS 命名规范,旨在提高代码的可读性和可维护性。BEM 规范通过明确的命名规则来定义组件和组件的各个部分,使开发者能够更容易地理解和维护代码。 BEM 命名规范的基本概念 Block&#xff08…...

idea大量爆红问题解决

问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...