Spring概念学习

概述

在此记录spring的学习内容。

概念

从前,在Java的大森林中,有一片神奇的土地,名叫"Spring"。这片土地上生长着各种美丽而强大的植物,它们分别象征着Spring框架中的各种功能和特性。

在这片土地上,有一位智慧而善良的园丁,名叫"Rod Johnson"。Rod是这片土地上的守护者,他有着非凡的见识和智慧。他注意到这片土地原本虽然生机盎然,但由于管理混乱、依赖杂乱等问题而日渐失去活力。于是,他开始策划着一场变革之旅。

Rod明白,为了让这片土地重焕生机,他需要一种全新的方式来管理这里那些繁杂的植物。于是,他提出了"控制反转"的理念,使得每一株植物可以有自己的生长空间,而不再依赖于别的植物。

随后,他又强调"依赖注入"这一概念,让每株植物可以从土地中获取所需的养分,而不用亲自去寻找。这样设计使得这些植物的生长变得更为高效。

Rod还发明了一种神奇的"面向切面编程"技术,一种能够让植物们自由组合、互相辅助的方式,令整片土地都焕发出一种特殊的生机。

渐渐地,这片土地上充满了生机与活力。每一株植物都在互相配合下茁壮成长,形成了一片绚丽而蓬勃的景象。园丁Rod Johnson因其智慧和勇气,被人们誉为这片土地上的英雄。

从那以后,人们便将这片土地上的新秩序称为"Spring",这个充满魔力的名字也因此广为传颂。而这位园丁Rod Johnson,则被尊称为Spring框架的缔造者和守护者。

就这样,Spring框架成为了Java世界中最重要的框架之一,为开发者们带来了许多便利,也为Java企业级应用开发带来了一场新的春天。

原文链接:https://blog.csdn.net/qq_55482652/article/details/137440957

控制反转

控制反转(Inversion of Control,IoC)是一种思想,是Spring框架的核心概念之一,它的主要作用是通过将对象的创建和依赖关系的管理交给Spring容器来实现更松耦合的设计,而不是由程序员显式地进行操作。

对比-传统开发

传统的开发模式中,应用程序本身负责创建和管理对象,并且通过直接调用其他对象的方法来完成业务逻辑。这种方式下,各个对象之间紧耦合,修改其中一个对象的实现会影响到其他所有相关的组件,导致代码的可维护性、可扩展性和可重用性都很差。

public class ServiceA {private ServiceB serviceB = new ServiceB();
}

这种方式中,ServiceA直接依赖于ServiceB的具体实现。

对比-控制反转IOC

Spring采用控制反转的方式解决了这个问题。它将对象的创建和管理职责从应用程序代码转移到了IOC容器。这样,对象不再自行创建依赖对象,而是从IOC容器中获取。在IoC容器中,对象的创建、依赖注入和生命周期的管理都由容器自动完成,使得组件之间的关系变得非常简单和清晰。具体来说,控制反转有两种主要方式:

  • 依赖注入(Dependency Injection, DI):通过构造器、setter方法或者字段注入的方式,将依赖对象注入到需要的对象中。
  • 依赖查找(Dependency Lookup):对象在运行时从容器中主动获取它所需要的依赖对象。

通过控制反转,Spring可以轻松实现面向对象设计中的依赖注入,即将对象所需的依赖关系从对象内部转移到外部(有点类似组合),从而消除了对象之间的硬编码关系,提高了代码的复用性和灵活性。同时,使得项目的结构更加清晰,易于维护。

对比总结

在传统的开发模式中,我们的程序主要由业务逻辑和控制逻辑组成。而在这种模式中,构建应用程序的过程通常是这样的:当需要一个对象时,我们会直接使用 new 运算符等方式来手动创建这个对象,并将其注入到其他对象中使用。这种过程中,创建和维护对象的职责完全由程序员负责。

而在IOC容器的设计思想下,控制权被完全反转了。即对象的创建和维护都交由外部容器管理,而程序员只需关注于定义依赖关系以及编写具体的业务逻辑(程序员只要确定需要什么依赖,并且关注业务逻辑即可,不用关心依赖对象的创建和维护)。实现这种控制反转的核心技术就是依赖注入、依赖查找。在Spring框架中,DI 通常通过三种方式进行:构造函数注入、 Setter 方法注入和字段注入。

总的来说,控制反转的目的是减少程序员对对象的手动创建和维护工作,实现代码重用、灵活性和可维护性。同时,依赖注入也使得程序的结构更加清晰,易于扩展和测试。因此,IOC容器和依赖注入已经成为了现代编程语言和框架中不可或缺的一部分。

IOC容器

IOC控制反转是一种思想,而在Spring框架中,负责创建、管理和注入依赖对象的容器就叫IOC容器(也可以叫做Bean容器)。

具体来说,当使用IOC容器时,我们将需要依赖的对象交给容器管理,而不是自行手动创建和维护这些对象。IOC容器会自动扫描项目中所有Bean定义,根据配置文件或者注解等方式实例化Bean对象,并将其注册到容器中。当我们需要使用某个依赖项时,只需要从容器中获取即可,而无需关心对象如何创建和维护。这种方式下,我们只需要关注业务逻辑的实现,从而使代码更加简洁、灵活和易于维护。

Spring框架中常用的IOC容器有两种:BeanFactory 和ApplicationContext。其中,BeanFactory 是Spring框架最基本的IOC容器,提供了最基本的IOC能力。ApplicationContext 是在BeanFactory 的基础上进行了扩展,提供了更多的特性和功能,例如国际化支持、AOP、事件机制等,因此是Spring框架中常用的IOC容器。

问题:IOC容器是如何管理依赖对象的?

依赖注入

依赖注入(Dependency Injection,DI)是一种应用程序设计模式,它将类之间的依赖关系从代码内部提取出来,转而通过外部容器进行管理。通过使用依赖注入,对象不再创建和维护它所依赖的其他对象,而是由 IOC 容器负责创建这些对象,并将其注入到需要使用它们的地方。依赖注入的核心思想是松耦合(loose coupling),也就是减少模块之间的依赖关系,使得系统更加灵活、易于扩展和维护。同时,依赖注入也有助于提高代码的可测试性,因为我们可以使用模拟对象来替代真实的依赖对象进行单元测试。
(说人话就是,依赖注入是从IOC容器中找到并使用所依赖对象的方法的一种抽象描述,可以理解为设计模式?)

实现依赖注入DI有3种方法:

  1. 构造器注入
  2. Setter方法注入
  3. 字段注入

构造器注入

构造器注入是通过构造函数将依赖注入到目标对象中的。这种方式确保了依赖对象在目标对象创建时即被提供,适用于强制性依赖。
示例:

@Component
public class ServiceA {private final ServiceB serviceB;@Autowiredpublic ServiceA(ServiceB serviceB) {this.serviceB = serviceB;}
}

优点:
确保依赖关系在对象创建时即被注入,不会出现未初始化的问题。
对于必须的依赖来说,构造器注入更加明确和安全。

缺点:
当依赖项较多时,构造函数的参数列表会变得很长,不太优雅。

Setter方法注入

Setter注入是通过setter方法将依赖注入到目标对象中的。适用于可选的依赖,或在对象创建之后进行依赖注入。
示例:

@Component
public class ServiceA {private ServiceB serviceB;@Autowiredpublic void setServiceB(ServiceB serviceB) {this.serviceB = serviceB;}
}

优点:
灵活性高,可以在对象创建之后再进行依赖注入。
适用于可选依赖和配置复杂对象。

缺点:
可能导致对象处于不完全初始化状态,增加了调试和维护的复杂性。

字段注入

字段注入是通过直接在字段上使用注解将依赖注入到目标对象中的。这种方式简单直观,但不推荐使用,因为违反了依赖倒置原则。

示例:

@Component
public class ServiceA {@Autowiredprivate ServiceB serviceB;
}

优点:
实现简单,代码简洁。

缺点:
使单元测试变得困难,因为依赖关系在对象创建之后无法更改。
违反了依赖倒置原则(Dependence Inversion Principle),使得类的设计不够优雅。

依赖注入方式总结

选择依赖注入方式的考虑

  • 构造器注入适用于强制性依赖,确保对象在创建时即被完全初始化。
  • Setter注入适用于可选依赖和需要在对象创建之后进行配置的情况。
  • 字段注入由于违反设计原则,通常不推荐使用,除非是在非常简单的场景中。

总结来说,选择合适的依赖注入方式应根据具体的需求和设计原则来决定。构造器注入和Setter注入是更推荐的方式,而字段注入应尽量避免。

代码比较:

假设我们有一个名为UserService的类,它需要依赖于UserDao类来进行数据存储。那么在传统的编程方式中,我们可能会这样写代码:

public class UserService {private UserDao userDao;public UserService() {this.userDao = new UserDao();}public void addUser(User user) {// 进行业务逻辑处理userDao.save(user);}// 其他方法省略...
}

在上述代码中,我们通过创建UserDao对象来满足UserService对依赖的需求。然而,这种方式会导致UserService和UserDao紧密耦合在一起,不利于代码的维护和扩展,并且使得UserService难以进行单元测试。

而如果使用依赖注入的话,我们可以将UserDao对象的创建和管理交给外部容器(如Spring容器)来完成,从而解耦和UserService与UserDao之间的关系,代码如下所示:

public class UserService {private UserDao userDao;public UserService(UserDao userDao) {this.userDao = userDao;}public void addUser(User user) {// 进行业务逻辑处理userDao.save(user);}// 其他方法省略...
}

在上述代码中,我们通过构造函数注入的方式将UserDao对象注入到了UserService类中,而UserDao对象则是由外部容器负责创建和管理的。这样一来,UserService与UserDao之间的耦合就被消除了,同时也提高了代码的可测试性和可维护性。

总的来说,依赖注入能够大大简化代码的编写和维护工作,使代码更加灵活、易于扩展和测试。

那这个UserDao是什么时候注入到UserService类中的呢?

UserDao对象是在创建UserService实例时通过依赖注入的方式注入到UserService类中的。具体来说,在使用Spring框架时,可以通过在配置文件中配置UserDao的实现类和UserService的构造函数参数来实现自动注入;或者使用@Autowired注解标记UserService类中的UserDao字段,让Spring容器自动完成注入。这样一来,当需要使用UserService对象时,Spring容器会自动创建一个UserDao对象并将其注入到UserService对象中。这样就实现了UserServiceUserDao之间的解耦合。

那这个创建的UserDao是单例吗?

在Spring容器中,默认情况下,所有的Bean都是单例的。也就是说,当使用依赖注入的方式创建UserDao对象时,默认情况下会创建一个单例对象,并且在整个应用程序的生命周期内都可以使用这个对象。如果需要创建多个实例,则需要在配置文件中进行相应的设置。可以使用@Scope注解来指定Bean的作用域,常见的作用域有单例(Singleton)、原型(Prototype)、请求(Request)、会话(Session)等。例如,可以使用@Scope("prototype")注解来将UserDao配置为原型作用域,这样每次从Spring容器中获取UserDao对象时,都会创建一个新的实例。

默认情况下会创建一个单例对象,并且在整个应用程序的生命周期内都可以使用这个对象。如果容器中已经创建了UserDao对象,则后续获取UserDao对象时不会再次创建新的对象,而是直接返回之前已经创建好的对象。

需要注意的是,在某些情况下,例如多线程环境下,使用单例模式可能会存在线程安全问题,此时建议将Bean的作用域配置为原型,这样可以每次都创建一个新的对象实例来避免线程安全问题。

面向切面编程

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

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

相关文章

wampserver安装与汉化

wampserver安装与汉化 文章目录 wampserver安装与汉化一、安装二、汉化1.升级软件并安装补丁 介绍: WampServer是一款由法国人开发的Apache Web服务器、PHP解释器以及MySQL数据库的整合软件包。免去了开发人员将时间花费在繁琐的配置环境过程,从而腾出更…

【Linux-GDB 调试】

Linux-GDB 调试 ■ scp 命令■ ubuntu 下通过 ssh 命令登录开发板■■■■■■ ■ scp 命令 scp 命令向其他主机发送文件。 ubuntu中向开发板发送文件 scp seriaApp sshd192.168.1.251 将 seriaApp 文件发送到开发板中,发送完成以后就会在开发板的根目录下看到…

每日一题——Python实现PAT甲级1042 Shuffling Machine(举一反三+思想解读+逐步优化)

一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 功能分析 时间复杂度 空间复杂度 总结 代码点评 我要更强 优化方向 …

stm32F4的时钟树

时钟其实就是单片机的心脏。首先我们的高速外部时钟(HES),看名字就可知道外部高速时钟是由外部所提供的其是高速的,其具体可以是有源晶振或者无源晶振所提供的时钟。而在时钟树图中我们从OSC_IN、OSC_OUT进入,然后经过…

Vue:现代前端开发的首选框架-【高级特性篇】

引言 在本篇博文中,我们将深入探索Vue.js框架的高级特性,包括路由管理、状态管理、表单处理、动画与过渡,以及服务端渲染(SSR)。这些进阶实践将帮助你提升Vue应用的架构和性能。 路由管理 Vue Router 介绍 Vue Rou…

【项目管理知识】项目质量管理措施

1、持续改进(PDCA) 戴明循环或称PDCA循环、PDSA循环。戴明循环的研究起源于20世纪20年代,先是有着“统计质量控制之父”之称的著名的统计学家沃特阿曼德休哈特(Walter A. Shewhart)在当时引入了“计划-执行-检查&…

低代码平台:教育机构数字化转型的技术新引擎

在数字化浪潮汹涌而来的今天,教育行业正迎来前所未有的变革。随着技术的不断进步和教育理念的更新,越来越多的教育机构开始意识到数字化转型的重要性。而在这场转型的浪潮中,低代码平台以其独特的优势,正成为教育机构实现数字化转…

7-13 字节解析(parse_byte)--PTA实验C++

一、题目描述 字节有几位都没个标准,古代程序员过的什么日子啊?还好现在字节统一成8位了。 鉴于我对C已有相当牢固的基础,可以探索底层开发了,先做个解析十六进制字节数据的功能吧。 输入规格 每项待读入的字节数据由两个非空白…

virtualbox识别windows上usb设备

当你插入 USB 时,你的宿主操作系统可以轻松访问它并使用其中的文件。如果需要VirtualBox 的虚拟机也能访问物理机的 USB设备,需要安装安装扩展包管理器。 第一步: 要安装 VirtualBox 扩展包,只需访问 VirtualBox 官方下载页面&a…

2024华为OD机试真题-出租车计费-C++(C卷D卷)

题目描述: 程序员小明打了一辆出租车去上班。出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。 出租车司机解释说他不喜欢数字4,所以改装了计费表,任何数字位置遇到数字4就直接跳过,其余功能都正常。 比如: 23再多一块钱就变为25;39再多一块钱变为50;399再…

深度学习-离线下载链接

1.torch安装包 https://download.pytorch.org/whl/torch/ 2.torchvision安装包 https://download.pytorch.org/whl/torchvision/ 持续更新...

骨传导耳机哪一款比较值得入手?年度精选好用骨传导耳机推荐

现在很多年轻人都会选择用骨传导耳机,因为骨传导耳机更加方便,不用入耳,不会伤害到耳朵,对耳膜也没有什么伤害。同时,因为骨传导耳机的结构也比较简单,所以佩戴也会更加舒适。接下来就给大家推荐几款口碑不…

LabVIEW老程序功能升级:重写还是改进?

概述:面对LabVIEW老程序的功能升级,开发者常常面临重写与改进之间的选择。本文从多个角度分析两种方法的利弊,并提供评估方法和解决思路。 重写(重新开发)的优势和劣势: 优势: 代码清晰度高&a…

面试二十七、 CAS和Atomic

CAS锁机制(无锁、自旋锁、乐观锁、轻量级锁)-CSDN博客 1. ABA问题 在C中,可以使用std::atomic和版本号来解决ABA问题。C标准库没有直接提供类似Java的AtomicStampedReference,但可以通过将版本号和指针组合在一起实现类似的效果。…

ESP32-C3模组上跑通OTA升级(10)

接前一篇文章:ESP32-C3模组上跑通OTA升级(9) 八、程序调试过程中遇到的问题及解决 前边各篇文章主要讲解了OTA的基础知识以及示例代码,但这其实是(远远)不够的,真正要在ESP32-C3芯片上跑通&…

【并发程序设计】13.信号机制

13.信号机制 概念: 信号机制是Unix、类Unix以及其他POSIX兼容的操作系统中的一种进程间通讯方式,它允许进程在发生特定事件时接收通知。 信号机制是操作系统中的一个重要概念,它提供了一种异步的通知机制,用于在进程之间传递消…

docker-compose 配置大全,持续更新

docker-compose 配置 安装docker-compose 1、执行脚本 由于github下载速度很慢,我将用到的程序放到了gitee仓库。 sudo curl -L https://gitee.com/brother_maolin/transfer/raw/master/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose2、执行,给予可执行…

6.s081通关小结

6.s081通关小结 终于是完成6.s081的所有lab了,感慨万千。已经忘了第一次听说这个lab是在什么时候了,只是模模糊糊地感觉是大三。那时的我第一次找到了刷题之外的新方向。但囿于小镇做题家对计算机认识的滞后性,什么Linux、Ubuntu之类的新系统…

【Python】解决Python报错:IndexError: queue index out of range

🧑 博主简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向…

【Unity Shader入门精要 第12章】屏幕后处理效果(二)

1. 卷积 在图像处理中,卷积操作就是使用一个卷积核对一张图像中的每个像素做一系列的操作。 卷积核通常是一个四方形网格结构,如2x2、3x3的方形区域,该区域内每个方格都有一个权重值。 当对图像中的某个像素进行卷积操作时,将卷…