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

在这里插入图片描述

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

💓 博客主页:从零开始的-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的代码如下所⽰:

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

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

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

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

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

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

  1. 使⽤外部包⾥的类,没办法添加类注解
  2. ⼀个类,需要多个对象,⽐如多个数据源
    这种场景,我们就需要使⽤⽅法注解 @Bean
    我们先来看看⽅法注解如何使⽤:
    ⽅法注解要配合类注解使⽤
@Component
public class BeanConfig {@Beanpublic 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;@Autowiredpublic 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;@Autowiredpublic 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;}@Beanpublic 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名称@Autowiredprivate 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.hqwc.cn/news/597010.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一点点金融

一点点金融 价值投资 需求 > 有限 > 不可逆 > 优势 > 长期持有者多趋势分析 改进MACD策略,使用涨跌幅比值RSI计算MACD原始MACD计算改进思路:使用涨跌幅比值RSI计算MACD 价值投资 需求 > 有限 > 不可逆 > 优势 > 长期持有者多…

使用AI开源引擎构建:智能文档处理系统提升企业生产效率

企业面临着海量文档的处理和管理挑战。智能文档处理技术(Intelligent Document Processing, IDP)应运而生,旨在通过人工智能(AI)技术提高文档处理的效率和准确性。本文将探讨IDP技术的核心功能、应用场景以及对企业效率…

RGB三通道和灰度值的理解

本文都是来自于chatGPT的回答!!! 目录 Q1:像素具有什么属性?Q2:图像的色彩是怎么实现的?Q3:灰度值和颜色值是一个概念吗?Q4:是不是像素具有灰度值,也有三个颜色分量RGB?Q5:灰度图像是没有色彩的吗?Q6: 彩色图像是既具有灰度值也具有RGB三…

数据流图

数据字典 数据流图平衡原则 父图与子图之间的平衡子图内平衡

Java中利用BitMap位图实现海量级数据去重

🏷️个人主页:牵着猫散步的鼠鼠 🏷️系列专栏:Java全栈-专栏 🏷️个人学习笔记,若有缺误,欢迎评论区指正 目录 前言 什么是BitMap?有什么用? 基本概念 位图的优势 …

多模态系列-综述Video Understanding with Large Language Models: A Survey

本文是LLM系列文章,针对《Video Understanding with Large Language Models: A Survey》的翻译。 论文链接:https://arxiv.org/pdf/2312.17432v2.pdf 代码链接:https://github.com/yunlong10/Awesome-LLMs-for-Video-Understanding 大型语言模型下的视频理解研究综述 摘要…

面试(02)————Java基础和集合

一、Java基础知识 1、面向对象的特征 2、Java 的基本数据类型有哪些 3、JDK JRE JVM 的区别 4、重载和重写的区别 5、Java中和equals的区别 6 、String、StringBuffer、StringBuilder三者之间的区别 7、接口和抽象类的区别是什么? 8、反射 9、jdk1.8 的新特…

C/C++预处理过程

目录 前言: 1. 预定义符号 2. #define定义常量 3. #define定义宏 4. 带有副作用的宏参数 5. 宏替换的规则 6. 宏和函数的对比 7. #和## 8. 命名约定 9. #undef 10. 命令行定义 11. 条件编译 12. 头文件的包含 13. 其他预处理指令 总结&#x…

JS详解-class-类的核心语法关于ES6与ES5

class基本核心语法: //定义类class Person{//公有属性(推荐此处定义)name// 定义属性并设置默认值price 100//构造函数constructor(name,age){// 构造函数内部的this实例化对象this.name namethis.age age// 动态添加属性(不推荐,查找麻烦)this.rank …

JavaScript-1(变量+数据类型+数据类型转换)

目录​​​​​​​ 1.计算机 编程语言 计算机基础 2.JS JS是什么 浏览器执行JS JS组成 ECMAScript DOM——文档对象模型 BOM——浏览器对象模型 JS写法 JS注释 JS输入输出语句 3.变量 变量的使用 变量使用注意点 变量小结 4.数据类型 变量的数据类型 基本…

Python免滑块验证脚本

说明 这是一个用于自动登录京东并更新Cookie到青龙管理系统的Python脚本。脚本支持通过账号密码自动登录,适用于需要定期更新京东Cookie的情况,特别是在使用青龙等自动化工具进行京东相关活动脚本运行时。 代码展示 全代码如下 # -*- coding: utf-8 -*- jdck.ini配置文件…

达托机器人(DRB)平台的安全性和前景是否可靠?

在当今数字化时代,技术创新不仅是企业成功的关键,也是整个行业的驱动力。在这个背景下,达托机器人(DRB)脱颖而出,以其创世团队的坚实基础和平台的可靠前景,引起了业界的广泛关注。 首先&#xf…