Java Spring IoCDI :探索Java Spring中控制反转和依赖注入的威力,增强灵活性和可维护性

news2024/11/18 4:34:37

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

💓 博客主页:从零开始的-CodeNinja之路

⏩ 收录文章:Java Spring IoC&DI :探索Java Spring中控制反转和依赖注入的威力,增强灵活性和可维护性

🎉欢迎大家点赞👍评论📝收藏⭐文章

目录

  • 前提小知识:高内聚低耦合
  • 一. IOC
    • 1.1 什么是IOC?
    • 1.2 IOC的实现
    • 1.3 IOC容器的优点
    • 1.4 IOC的存储
        • @Controller(控制器存储)
        • @Service(服务存储)
        • @Repository(仓库存储)
        • @Component(组件存储)
        • @Configuration(配置存储)
        • @Bean (方法注解)
    • 1.5 IOC注解总结概括
  • 二. DI
    • 2.1 什么是DI?
    • 2.2 DI的方法使用
        • 属性注入
        • 构造方法注入
        • Setter注入
        • 三种注入优缺点分析
    • 2.3 @Autowired存在的问题
        • @Primary
        • @Qualifier
        • @Resource
    • 2.4 @Autowird的注入流程图
  • 三. 总结

前提小知识:高内聚低耦合

我们一下要学习的内容都是为了实现⾼内聚低耦合来进行的
软件设计原则:⾼内聚低耦合.
⾼内聚指的是:⼀个模块中各个元素之间的联系的紧密程度,如果各个元素(语句、程序段)之间的联
系程度越⾼,则内聚性越⾼,即"⾼内聚"。
低耦合指的是:软件中各个层、模块之间的依赖关联程序越低越好。修改⼀处代码,其他模块的代码
改动越少越好.
在这里插入图片描述
⾼内聚低耦合⽭盾吗?
不⽭盾,⾼内聚指的是⼀个模块中各个元素之间的联系的紧密程度,低耦合指的是各个模块之间的紧
密程度
这就好⽐⼀个企业,包含很多部⻔,各个部⻔之间的关联关系要尽可能的⼩,⼀个部⻔发⽣问题,要尽
可能对降低对其他部⻔的影响,就是耦合.但是部⻔内部员⼯关系要尽量紧密,遇到问题⼀起解决,克
服.这叫做内聚.
⽐如邻⾥邻居,楼上漏⽔,楼下遭殃,就是耦合.家庭⼀个成员⽣病,其他成员帮忙照顾,就叫内聚.
⼀个家庭内部的关系越紧密越好,⼀个家庭尽可能少的影响另⼀个家庭,就是低耦合.
简单来说:就是在未来的工作中写出的代码尽量集中在一个路径中,但是每个程序与其它程序的关联度很低,以至于一个文件出错了并不影响其它程序的正常运行.

一. IOC

1.1 什么是IOC?

IoC是Spring的核⼼思想,也是常⻅的⾯试题,那什么是IoC呢?
IoC:InversionofControl(控制反转),也就是说Spring是⼀个"控制反转"的容器.
什么是控制反转呢?也就是控制权反转.什么的控制权发⽣了反转?获得依赖对象的过程被反转了
也就是说,当需要某个对象时,传统开发模式中需要⾃⼰通过new创建对象,现在不需要再进⾏创
建,把创建对象的任务交给容器,程序中只需要依赖注⼊(DependencyInjection,DI)就可以了.
我们⽤⼀句更具体的话来概括Spring,那就是:Spring是包含了众多⼯具⽅法的IoC容器
简单点来说:就是通过IOC的内置注解将被注解的内容放到Spring的大池子里,方便后续的调用(这样子应该很好理解)

1.2 IOC的实现

举个栗子:比如传统的造车过程是一级级的调用,如下:
在这里插入图片描述
以上程序的问题是:当最底层代码改动之后,整个调⽤链上的所有代码都需要修改.程序的耦合度⾮常⾼(修改⼀处代码,影响其他处的代码修改)

经过IOC实现后的流程图如下:
在这里插入图片描述
而IOC的目标就是为了降低耦合度,对于上面的例子来说就是将汽车每个部件的生产都交给第三方来处理,不让他们之间有联系,也就降低了耦合度
我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是Car控制并创建了
Framework,Framework创建并创建了Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再
是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由
当前类控制了.
这样的话,即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是IoC的
实现思想。

1.3 IOC容器的优点

资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。第⼀,资源集
中管理,实现资源的可配置和易管理。第⼆,降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合
度。

  1. 资源集中管理:IoC容器会帮我们管理⼀些资源(对象等),我们需要使⽤时,只需要从IoC容器中去取
    就可以了
  2. 我们在创建实例的时候不需要了解其中的细节,降低了使⽤资源双⽅的依赖程度,也就是耦合度.
    Spring就是⼀种IoC容器,帮助我们来做了这些资源管理.

1.4 IOC的存储

在之前的⼊⻔案例中,要把某个对象交给IOC容器管理,需要在类上添加⼀个注解: @Component
⽽Spring框架为了更好的服务web应⽤程序,提供了更丰富的注解.
共有两类注解类型可以实现:

  1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration.
  2. ⽅法注解:@Bean.
    接下来我们分别来看
@Controller(控制器存储)

使⽤@Controller存储bean的代码如下所⽰:

	@Controller // 将对象存储到 Spring 中
	public class UserController {
		public void sayHi(){
			System.out.println("hi,UserController...");
		}
	}
@Service(服务存储)

使⽤@Service存储bean的代码如下所⽰:

	@Service// 将对象存储到 Spring 中
	public class UserService {
		public void sayHi(String name) {
			System.out.println("Hi," + name);
		}
	}
@Repository(仓库存储)

使⽤ @Repository 存储bean的代码如下所⽰:

	@Repository
	public class UserRepository {
		public void sayHi() {
			System.out.println("Hi, UserRepository~");
		}
	}
@Component(组件存储)

使⽤@Component存储bean的代码如下所⽰:

	@Component
	public class UserComponent {
		public void sayHi() {
			System.out.println("Hi, UserComponent~");
		}
	}
@Configuration(配置存储)

使⽤@Configuration存储bean的代码如下所⽰:

	@Configuration
	public class UserConfiguration {
		public void sayHi() {
			System.out.println("Hi,UserConfiguration~");
		}
	}
@Bean (方法注解)

类注解是添加到某个类上的同时⽅法注解要配合类注解使⽤,但是存在两个问题:

  1. 使⽤外部包⾥的类,没办法添加类注解
  2. ⼀个类,需要多个对象,⽐如多个数据源
    这种场景,我们就需要使⽤⽅法注解 @Bean
    我们先来看看⽅法注解如何使⽤:
    ⽅法注解要配合类注解使⽤
@Component
public class BeanConfig {
	@Bean
	public User user(){
		User user = new User();
		user.setName("zhangsan");
		user.setAge(18);
		return user;
	}
}

1.5 IOC注解总结概括

  • @Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.

  • @Servie:业务逻辑层,处理具体的业务逻辑.

  • @Repository:数据访问层,也称为持久层.负责数据访问操作

  • @Configuration:配置层.处理项⽬中的⼀些配置信息.

  • @Component:其它4大类注解的父类

  • @Bean:方法注解,将一个方法交给Spring管理,同时要与类注解一起搭配使用

其实这些注解⾥⾯都有⼀个注解 @Component ,说明它们本⾝就是属于 @Component 的"⼦类".@Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller , @Service ,
@Repository 等.这些注解被称为 @Component 的衍⽣注解.
@Controller , @Service 和 @Repository ⽤于更具体的⽤例(分别在控制层,业务逻辑层,持
久化层),在开发过程中,如果你要在业务逻辑层使⽤ @Component 或@Service,显然@Service是更
好的选择

二. DI

2.1 什么是DI?

DI:DependencyInjection(依赖注⼊)
容器在运⾏期间,动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。
程序运⾏时需要某个资源,此时容器就为其提供这个资源.
从这点来看,依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过
引⼊IoC容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。
上述代码中,是通过构造函数的⽅式,把依赖对象注⼊到需要使⽤的对象中的
可以说,DI是IoC的⼀种实现

2.2 DI的方法使用

依赖注⼊是⼀个过程,是指IoC容器在创建Bean时,去提供运⾏时所依赖的资源,⽽资源指的就是对象.
在上⾯程序案例中,我们使⽤了 @Autowired 这个注解,完成了依赖注⼊的操作.
简单来说,就是把对象取出来放到某个类的属性中.
在⼀些⽂章中,依赖注⼊也被称之为"对象注⼊",“属性装配”,具体含义需要结合⽂章的上下⽂来理解
关于依赖注⼊,Spring也给我们提供了三种⽅式:

  1. 属性注⼊(FieldInjection)
  2. 构造⽅法注⼊(ConstructorInjection)
  3. Setter注⼊(SetterInjection)
属性注入

属性注⼊是使⽤ @Autowired 实现的,将Service类注⼊到Controller类中.
Service类的实现代码如下:

import org.springframework.stereotype.Service;
@Service
public class UserService {
		public void sayHi() {
			System.out.println("Hi,UserService");
		}
}
构造方法注入

构造⽅法注⼊是在类的构造⽅法中实现注⼊,如下代码所⽰:

@Controller
public class UserController2 {
	//注⼊⽅法2: 构造⽅法
	private UserService userService;
	@Autowired
	
	public UserController2(UserService userService) {
		this.userService = userService;
	}
	public void sayHi(){
		System.out.println("hi,UserController2...");
		userService.sayHi();
	}
}

注意事项:如果类只有⼀个构造⽅法,那么@Autowired注解可以省略;如果类中有多个构造⽅法,
那么需要添加上@Autowired来明确指定到底使⽤哪个构造⽅法。

Setter注入

Setter注⼊和属性的Setter⽅法实现类似,只不过在设置set⽅法的时候需要加上@Autowired注
解,如下代码所⽰:

@Controller
public class UserController3 {
	//注⼊⽅法3: Setter⽅法注⼊
	private UserService userService;


	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
	
	public void sayHi(){
		System.out.println("hi,UserController3...");
		userService.sayHi();
	}
}
三种注入优缺点分析
  1. 属性注⼊

优点:简洁,使⽤⽅便;

缺点:

  • 只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指针异常)
  • 不能注⼊⼀个Final修饰的属性
  1. 构造函数注⼊

优点:

  • 可以注⼊final修饰的属性
  • 注⼊的对象不会被修改
  • 依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法 是在类加载阶段就会执⾏的⽅法.
  • 通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的

缺点:
注⼊多个对象时,代码会⽐较繁琐

  1. Setter注⼊

优点:⽅便在类实例之后,重新对该对象进⾏配置或者注⼊

缺点:

  • 不能注⼊⼀个Final修饰的属性
  • 注⼊对象可能会被改变,因为setter⽅法可能会被多次调⽤,就有被修改的⻛险.

2.3 @Autowired存在的问题

当同⼀类型存在多个bean时,使⽤@Autowired会存在问题
报错的原因是,⾮唯⼀的Bean对象。
如何解决上述问题呢?Spring提供了以下⼏种解决⽅案:
• @Primary
• @Qualifier
• @Resource

@Primary

使⽤@Primary注解:当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现.

@Component
public class BeanConfig {

	@Primary //指定该bean为默认bean的实现
	@Bean("u1")
	public User user1(){
		User user = new User();
		user.setName("zhangsan");
		user.setAge(18);
		return user;
	}
	
	@Bean
	public User user2() {
		User user = new User();
		user.setName("lisi");
		user.setAge(19);
		return user;
	}
}
@Qualifier

使⽤@Qualifier注解:指定当前要注⼊的bean对象。在@Qualifier的value属性中,指定注⼊的bean
的名称。
• @Qualifier注解不能单独使⽤,必须配合@Autowired使⽤

@Controller
public class UserController {
	@Qualifier("user2") //指定bean名称
	@Autowired
	private User user;
	
	public void sayHi(){
		System.out.println("hi,UserController...");
		System.out.println(user);
	}
}
@Resource

使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。

@Controller
public class UserController {
	@Resource(name = "user2")
	private User user;
	
	public void sayHi(){
		System.out.println("hi,UserController...");
		System.out.println(user);
	}
}

2.4 @Autowird的注入流程图

在这里插入图片描述

常见⾯试题:
@Autowird与@Resource的区别
• @Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解
• @Autowired默认是按照类型注⼊,⽽@Resource是按照名称注⼊.相⽐于@Autowired来说,
@Resource⽀持更多的参数设置,例如name设置,根据名称获取Bean。

三. 总结

Java Spring框架中的IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)是框架的核心概念之一,它们旨在降低组件之间的耦合度,提高代码的灵活性和可维护性。

  • 控制反转(IoC):在传统的程序设计中,应用程序控制程序的流程,即应用程序负责实例化和管理对象之间的依赖关系。而在IoC容器中,控制权被转移到容器,容器负责实例化对象并管理它们之间的依赖关系。这种控制权的转移使得组件之间的耦合度降低,提高了代码的灵活性和可测试性。

  • 依赖注入(DI):依赖注入是IoC的一种实现方式,通过依赖注入,容器会将一个对象所依赖的其他对象注入到该对象中,而不是由对象自己去创建或查找依赖的对象。依赖注入可以通过构造函数、属性或者方法进行注入,使得组件之间的依赖关系更加清晰、可控,同时也方便进行单元测试和替换依赖。

总的来说,IoC和DI通过将控制权交给容器,实现了组件之间的解耦和松耦合,提高了代码的可维护性、可测试性和可扩展性,是Spring框架的核心特性之一。

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

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

相关文章

16-代码随想录206反转链表

16-代码随想录206反转链表 206.反转链表 力扣题目链接(opens new window) 题意:反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 206. 反转链表 给你单链表的头节点 head ,请你反转链表&…

RTX RTOS 操作实例分析之---线程(thread)

0 Preface/Foreword 1 线程(thread) 1.1 线程定义 1.1.1 USE_BASIC_THREADS(宏定义) 经过以上步骤(makefile包含),USE_BASIC_THREADS在编译阶段被定义到相应的模块中。 1.1.2 定义线程ID变量…

博客部署004-centos安装mysql及redis

1、如何查看当前centos版本? cat /etc/os-release 2、安装mysql 我的是centos8版本,使用dnf命令 2.1 CentOS 7/8: sudo yum install -y mysql-community-server 或者在CentOS 8上,使用DNF:🌟 sudo dnf install -y mysql-ser…

无尽加班何时休--状态模式

1.1 加班,又是加班! 公司的项目很急,所以要求加班。经理把每个人每天的工作都排得满满的,说做完就可以回家,但是没有任何一个人可以在下班前完成的,基本都得加班,这就等于是自愿加班。我走时还有…

[技术闲聊]我对电路设计的理解(七)-Cadence原理图绘制

一、原理图软件推荐 之前的章节有讲过AD、PADS、Cadence,以及三者的应用标准,今天再讲讲这一点。 如果是学生,可以学习AD软件,因为学校在学习,上手容易,而且即使工作后,如果是电机控制等4层板或…

数据劫持的冲突问题

在近段时间我又再一次使用了数据劫持,发现了一些冲突问题,并在此介绍我所应用的场景。 一、冲突问题 在之前的文章中有介绍过数据劫持,但后来使用的很少,最近在一次使用的过程中,发现了一些问题。 1.value属性的冲突…

第十四届蓝桥杯省赛大学C组(C/C++)填充

原题链接:填充 有一个长度为 n 的 01 串,其中有一些位置标记为 ?,这些位置上可以任意填充 0 或者 1,请问如何填充这些位置使得这个 01 串中出现互不重叠的 0 和 1 子串最多,输出子串个数。 输入格式 输入一行包含一…

【51单片机学习记录】超声波测距

一、超声波测距概述 (1)超声波时间差测距原理 超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时。超声…

环形链表 - LeetCode 热题 25

大家好!我是曾续缘🥰 今天是《LeetCode 热题 100》系列 发车第 25 天 链表第 4 题 ❤️点赞 👍 收藏 ⭐再看,养成习惯 环形链表 给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可…

道路病害的检测与评估

基于yolov8道路病害的检测与评估 1 安装yolov8并使用 1.下载后: 2.选择为所有用户安装 3.选择一个合适的目录 4.第一个是自动添加环境变量,我们用默认的第二个后边手动添加 5.等待安装 1.1 安装anconda并配置环境变量 安装完成anconda之后,主要用的两个为Anaconda Prompt …

用树莓派获取传感器数据通过Onenet云平台(物模型)传输至微信小程序(上)

前言 为了传输传感器数据,在网上找了很多方法,但都因为各种各样的问题最终没能成功实现。最终找到这个既简单,又方便实现的方法。步骤有点多,希望大家可以跟着教程,一步步耐心的做下去,愿大家都能成功实现数…

ubuntu系统安装systemc-2.3.4流程

背景:systemC编程在linux下的基础环境配置 1,下载安装包,并解压 (先下载了最新的3.0.0,安装时候显示sc_cmnhdr.h:115:5: error: #error **** SystemC requires a C compiler version of at least C17 **** &#xff…

idea开发 java web 高校学籍管理系统bootstrap框架web结构java编程计算机网页

一、源码特点 java 高校学籍管理系统是一套完善的完整信息系统,结合java web开发和bootstrap UI框架完成本系统 ,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 前段主要技术 css jq…

【云计算】云数据中心网络(一):VPC

云数据中心网络(一):VPC 1.什么是 VPC2.VPC 的组成2.1 虚拟交换机2.2 虚拟路由器 3.VPC 网络规划3.1 VPC 数量规划3.2 交换机数量规划3.3 地址空间规划3.4 不同规模企业地址空间规划实践 4.VPC 网络高可靠设计4.1 单地域单可用区部署4.2 单地…

【鸿蒙 HarmonyOS】@ohos.promptAction (弹窗)

一、背景 创建并显示文本提示框、对话框和操作菜单。 文档地址👉:文档中心 说明 本模块首批接口从API version 9开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。 该模块不支持在UIAbility的文件声明处使用,即…

Premiere Pro 2024:赋予创意翅膀,让你的视频飞翔 mac/win版

Premiere Pro 2024,作为Adobe旗下的旗舰视频编辑软件,自推出以来,一直在视频制作领域占据着重要的地位。随着技术的不断进步和创新,Premiere Pro 2024为用户带来了前所未有的编辑体验,重新定义了视频制作的标准。 Pre…

爬虫 新闻网站 以湖南法治报为例(含详细注释) V1.0

目标网站:湖南法治报 爬取目的:为了获取某一地区更全面的在湖南法治报已发布的宣传新闻稿,同时也让自己的工作更便捷 环境:Pycharm2021,Python3.10, 安装的包:requests,csv&#xff…

刷题之Leetcode283题(超级详细)

283.移动零 283. 移动零https://leetcode.cn/problems/move-zeroes/ 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nu…

深度剖析鞋服品牌商品数字化管理的重要性

随着信息技术的迅猛发展与市场竞争的加剧,鞋服品牌商品数字化管理的重要性愈发凸显。数字化管理不仅关乎企业运营效率的提升,更是品牌实现差异化竞争、提升顾客体验、构建智慧零售生态的关键所在。对于鞋服品牌企业而言,提升商品数字化管理的…

P2089 烤鸡、P1706 全排列问题、P1157 组合的输出、P1036 [NOIP2002 普及组] 选数——Python代码实现(带注释)

P2089 烤鸡 题目背景 猪猪 Hanke 得到了一只鸡。 题目描述 猪猪 Hanke 特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke 吃鸡很特别,为什么特别呢?因为他有 1010 种配料(芥末、孜然等&#xf…