Spring原理-IOC和AOP

概述

在此记录spring的学习内容。spring官网:https://spring.io/
在这里插入图片描述

概念故事

从前,在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

控制反转IOC

控制反转

控制反转(Inversion of Control,IoC)是一种思想,是Spring框架的核心概念之一,它的主要作用是通过将对象的创建和依赖关系的管理交给Spring容器来实现更松耦合的设计,而不是由程序员显式地进行操作。
一句话理解IOC、IOC容器、依赖注入:IOC是一种思想。通过IOC容器管理对象。编码时,通过依赖注入的方式从IOC容器中获取依赖的对象。
IOC容器->创建对象
DI->给对象的属性赋值

对比-传统开发

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

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;

    @Autowired
    public ServiceA(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

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

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

Setter方法注入

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

@Component
public class ServiceA {
    private ServiceB serviceB;

    @Autowired
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

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

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

字段注入

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

示例:

@Component
public class ServiceA {
    @Autowired
    private 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的作用域配置为原型,这样可以每次都创建一个新的对象实例来避免线程安全问题。

IOC实现原理

spring提供两种方式创建Bean,一种是xml,一种是注解。

基于XML的原理

读取解析xml配置文件->反射实例化对象->存储在Map集合中

1 读xml

读取配置文件(spring.xml)->xml解析->获取bean的id和类的全路径名

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="empDao" class="com.zou.learnspring.dao.impl.EmpDaoImpl2"/>

</beans>

补充
bean标签的属性: 点击跳转

2 实例化对象

通过反射实例化对象->全路径名获取字节码对象->通过字节码实例化->放到容器中(当作一个Map集合)
Class clazz = Class.forName(“com.zou.learnspring.dao.impl.EmpDaoImpl2”)
Object obj = clazz.newInstance();
map.put(“empDao”, obj);

3 getBean获取对象

工厂模式返回Bean对象
BeanFactory接口定义的getBean方法,该方法底层就是map.get(“name”);

接口的继承ApplicationContext -> … -> BeanFactory
ApplicationContext的实现类:ClassPathXmlApplicationContext。其中间也是间接实现了ApplicationContext接口。
在idea中,在ApplicationContext接口中,通过Ctrl+H可以查看接口的实现类
在这里插入图片描述

面向切面编程

作用:事务控制、日志记录、性能检测、权限控制

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW调用第三方硬件DLL常见问题及开发流程

在LabVIEW中调用第三方硬件DLL时&#xff0c;除了技术问题&#xff0c;还涉及开发流程、资料获取及与厂家的沟通协调。常见问题包括函数接口不兼容、数据类型转换错误、内存管理问题、线程安全性等。解决这些问题需确保函数声明准确、数据类型匹配、正确的内存管理及线程保护。…

金钱世界:资本主义的未来

概述 《金钱世界&#xff1a;资本主义的未来》是一部探讨资本主义未来、全球经济停滞、大型全球企业与国家关系以及贫富差距问题的纪录片。纪录片分集内容&#xff1a;该纪录片共分为3集&#xff0c;每集都聚焦于不同的主题&#xff1a; 第一集《世界会继续发展吗&#xff1f…

QT实现动态翻译切换

1、实现QT动态中英文切换效果 效果如下: 2、原理 因为软件本身就是中文版,所以只需准备一个英文版的翻译即可,,那就是将所有需要翻译的地方用tr包裹,然后首先执行lupdate更新一下,接着用qt的翻译软件 Qt Linguist打开ts文件进行翻译,然后保存,最后使用 lrelease发布一…

小白跟做江科大32单片机之旋转编码器计次

原理部分按照下面这个链接理解即可y小白跟做江科大32单片机之对射式红外传感器计次-CSDN博客https://blog.csdn.net/weixin_58051657/article/details/139350487https://blog.csdn.net/weixin_58051657/article/details/139350487 实验过程 1.按照江科大老师给的电路图进行连接…

音视频开发—V4L2介绍,FFmpeg 打开摄像头输出yuv文件

实验平台&#xff1a;Ubuntu20.04 摄像头&#xff1a;1080P 监控摄像头&#xff0c;采用V4L2驱动框架 文章目录 1.V4L2相关介绍1.1. 基本概念1.2. 主要功能1.3. V4L2驱动框架1.4. 主要组件1.5. 使用V4L2的应用1.6. 常用V4L2工具 2.ffmpeg命令实现打开摄像头输出yuv文件3.使用C…

文献阅读:GCNG:用于从空间转录组数据推断基因相互作用的图卷积网络

文献介绍 「文献题目」 GCNG: graph convolutional networks for inferring gene interaction from spatial transcriptomics data 「研究团队」 Ziv Bar-Joseph&#xff08;美国卡内基梅隆大学&#xff09; 「发表时间」 2020-12-10 「发表期刊」 Genome Biology 「影响因子…

一文搞懂分布式事务Seta-AT模式实现原理

分布式事务概念 分布式事务&#xff08;Distributed Transaction&#xff09; 是指在分布式系统中&#xff0c;涉及多个数据库、服务、消息队列等资源&#xff0c;并且需要保证这些资源上的操作要么全部成功提交&#xff0c;要么全部失败回滚的一种机制。在分布式系统中&#…

极简网络用户手册(1)

极简网络系统处理流程 模块位置&#xff1a;参数平台--专题分析--极简网络分析 步骤&#xff1a; 步骤一&#xff1a;创建精细化场景策略 步骤二&#xff1a;创建任务&#xff0c;主要选择策略&#xff08;包括√配置和距离配置&#xff09;和需要处理的小区清单&#xff08;源…

vulhub中Nexus Repository Manager 3 未授权目录穿越漏洞(CVE-2024-4956)

Nexus Repository Manager 3 是一款软件仓库&#xff0c;可以用来存储和分发Maven、NuGET等软件源仓库。 其3.68.0及之前版本中&#xff0c;存在一处目录穿越漏洞。攻击者可以利用该漏洞读取服务器上任意文件。 环境启动后&#xff0c;访问http://your-ip:8081即可看到Nexus的…

德克萨斯大学奥斯汀分校自然语言处理硕士课程汉化版(第四周) - 语言建模

语言建模 1. 统计语言模型2. N-gram语言建模 2.1. N-gram语言模型中的平滑处理 3. 语言模型评估4. 神经语言模型5. 循环神经网络 5.1. Vanilla RNN5.2. LSTM 1. 统计语言模型 统计语言模型旨在量化自然语言文本中序列的概率分布&#xff0c;即计算一个词序列&#xff08;如一…

【记忆化搜索】2318. 不同骰子序列的数目

本文涉及知识点 记忆化搜索 LeetCode 2318. 不同骰子序列的数目 给你一个整数 n 。你需要掷一个 6 面的骰子 n 次。请你在满足以下要求的前提下&#xff0c;求出 不同 骰子序列的数目&#xff1a; 序列中任意 相邻 数字的 最大公约数 为 1 。 序列中 相等 的值之间&#xff…

重庆耶非凡科技有限公司的选品师项目加盟靠谱吗?

在当今电子商务的浪潮中&#xff0c;选品师的角色愈发重要。而重庆耶非凡科技有限公司以其独特的选品师项目&#xff0c;在行业内引起了广泛关注。对于想要加盟该项目的人来说&#xff0c;项目的靠谱性无疑是首要考虑的问题。 首先&#xff0c;我们来看看耶非凡科技有限公司的背…

图解 IPv6 多播范围

1、 IPv6 多播范围 2、从单播地址生成请求节点多播地址 3、已分配的多播地址

Day04 左侧菜单导航实现

一.点击左侧菜单导航到对应的View页面 1.首先在MyToDo项目中,创建出左侧菜单所有的View(视图)及对应的ViewModel(视图逻辑处理类) ViewViewModel首页IndexViewIndexViewModel待办事项ToDoViewToDoViewModel忘备录MemoViewMemoViewModel设置SettingsViewSettingsViewModel

制作一个简单HTML旅游网站(HTML+CSS+JS)云南旅游网页设计与实现5个页面

一、&#x1f468;‍&#x1f393;网站题目 旅游&#xff0c;当地特色&#xff0c;历史文化&#xff0c;特色小吃等网站的设计与制作。 二、✍️网站描述 云南旅游主题的网页 一共七个个页面 - 旅游网页使用html css js制作 有banana图 - 页面可以相互跳转 包含表单 三级页面…

XFeat:速度精度远超superpoint的轻量级图像匹配算法

代码地址&#xff1a;https://github.com/verlab/accelerated_features?tabreadme-ov-file 论文地址&#xff1a;2404.19174 (arxiv.org) XFeat (Accelerated Features)重新审视了卷积神经网络中用于检测、提取和匹配局部特征的基本设计选择。该模型满足了对适用于资源有限设备…

sqlite基本操作

简介 文章目录 简介1.数据库的安装2.数据库命令&#xff1a;API&#xff0c;创建表单代码 csprintf&#xff08;&#xff09;getchar和scanf&#xff08;&#xff09; 1.数据库的安装 sudo dpkg -i *.deb这个报错表明出现依赖问题 用这个命令后再试试sudo apt --fix-broken in…

Nocobase快速上手 - 开发第一个插件

在前面的几篇博文中&#xff0c;记录了在Nocobase中配置collection和界面&#xff0c;这篇文章开始插件的开发。插件可以扩展Nocobase的业务能力&#xff0c;解锁更强大的功能。 环境搭建 创建插件需要配置nocobase的开发环境&#xff0c;笔者采用的是clone 官方代码repo的方…

【Centos7】解决 CentOS 7 中出现 “xx: command not found“ 错误的全面指南

【Centos7】初探xx:command not found解决方案 大家好 我是寸铁&#x1f44a; 【Centos7】解决 CentOS 7 中出现 “xx: command not found” 错误的全面指南✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 经常有小伙伴问我&#xff0c;xx:command not found怎么办&#xff1…

GPT-4o如何重塑AI未来!

如何评价GPT-4o? 简介&#xff1a;最近&#xff0c;GPT-4o横空出世。对GPT-4o这一人工智能技术进行评价&#xff0c;包括版本间的对比分析、GPT-4o的技术能力以及个人感受等。 GPT-4o似乎是一个针对GPT-4模型进行优化的版本&#xff0c;它在性能、准确性、资源效率以及安全和…