浅谈Spring的相关概念性问题 IOC DI AOP 工厂模式 单例

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 浅谈Spring的相关概念性问题 IOC DI AOP 工厂模式 单例

在我的理想观点中,软件的开发分为前端开发和后端开发;前端开发就是用Vue、Ext等JavaScript框架做出各种华丽的界面,直接面向用户,把用户的相关操作转化成指定形式,发给后端;后端开发就是从前端接取数据,对数据库进行增删改查。

其实一年前老师就让我们接触一下SSM框架,可那时的我还在沉迷Java的文件读写、GUI那一块,还有就是微信公众号。我在前几天看着视频学者搭建了SSM的开发环境,大致看懂了代码,然后翻博客,找知乎,初步理解了SSM中一些概念性问题,这里做一个整理。

Spring本质上是一个库,它提供了软件框架的功能,使软件之间的逻辑更加清晰,配置更灵活,Spring使用AOP和IoC,而AOP和IoC是一种思想。

在总结的时候可能用到其他博客的内容,参考网址写在最后面。

 

IOC 控制反转

书本定义

原先需要实现的对象创建、维护对象间的依赖关系,反转给容器帮忙实现。

看不懂很正常,请接着看下去

应用背景

采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。

例如我们家里挂的时钟,秒针转一圈之后,分针转一小格;同理分针转一圈,时针转一大格。

在面向对象编程中,即当秒针转了一圈的时候,秒针对象就要new一个分针对象,然后让分针的值+1,然后秒针的值归零。我们可以看出,秒针对象的正常运行需要分针对象,我们可以说是一种依赖关系,即秒针依赖于分针。(假设对象为单例)

如果我们打开时钟的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针、分针和秒针顺时针旋转,从而在表盘上产生正确的时间。上图中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务。我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组的正常运转。

面向对象编程中的“耦合关系”,就好比齿轮组中齿轮之间的啮合关系。对象之间的耦合关系是无法避免的,也是必要的,这是协同工作的基础。但是,伴随着编程开发的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,对象之间耦合度过高的系统,必然会出现牵一发而动全身的情形。

所以我们必须要想办法优化这一个方面,即所谓实现对象之间的“解耦”,它是为了解决对象之间的耦合度过高的问题。好了,IOC这就来了。

IOC是什么

借助于“第三方”实现具有依赖关系的对象之间的解耦

spring IOC容器负责创建Bean,并通过容器将Bean注入到需要Bean的对象上。

还是刚刚的例子,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系。

这时候,A、B、C、D这4个对象之间已经没有了耦合关系了,秒针转了一圈,只需要告诉IOC容器,我转了一圈了,IOC就会把分针的值加1;这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现IOC容器,对于系统开发而言,参与开发的每一成员只要实现自己的事情就可以了,别人的跟我没有任何关系

具体实现

还是刚刚的例子,设对象A为时钟的秒针,对象B是时钟的分针。

软件系统在没有引入IOC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。在引入IOC容器之后,这种情形就完全改变了。由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了。


就比如,我们是如何找女朋友的?大学里,我们会到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、微信、电话……,想办法认识她们,投其所好送其所要,然后嘿嘿……这个过程是很繁琐的,我们要在需要谈恋爱的时候,去手动new一个出来。传统的编程开发也是这样,在一个对象中,如果要使用另外的对象,就必须自己new一个,使用完之后还要将对象销毁。

那么有了IOC之后,有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚介。婚介管理了很多男男女女的资料,我可以向婚介告知一个需求,告诉它我想找个什么样的女朋友,比如身高一米七,等等等等,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。

DI 依赖注入

通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

通俗来讲,在软件系统运行过程中,对象A需要依赖对象B的时候,IOC容器动态的向对象A传输它需要的对象B这个传输的过程叫做注入,注入了什么?就是注入了依赖,所以全称叫做依赖注入。

比如说对象A某个时候需要连接数据库(A需要依赖Connection),原本需要自己new一个Connection对象,有了IOC之后,我们只需要告诉IOC,我需要Connection;IOC会在适当的时候创建Connection对象,至于什么时候创建,则么创建,不需要让对象A知道。那么IOC在向对象A传递Connection对象,我们叫做注入,就好比打针一样,把Connection对象注入到对象A中。

还有一个概念——反射:它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性。

spring就是通过反射来实现依赖注入的。

单例模式

即一个类实例化的对象唯一,例如Windows中的任务管理器,只能打开一个。具体可通过相关代码来实现,比如在类内部实例化私有对象,通过public方法调用该对象。

简单工厂模式

实质是由一个工厂类根据传入的参数, 动态决定应该创建哪一个产品类,就是暴力的if-else。原先是通过new方法实例化,现在只需要实例化一个工厂类,传入一个参数告诉工厂类你要什么,就可以获取你要的对象。比如传入一个"dog"字符串,返回给你一个狗对象。

工厂模式

假设有10个产品,那么该工厂模式有1个抽象父类工厂Factory(可以是接口、抽象类、具体类),该父类包含未实现工厂方法;接着有10个具体工厂子类,一一对应这10个产品类,因为父类工厂Factory未实现的工厂方法由子类来负责实现,不同具体工厂子类可以创建不同具体产品。工厂模式使得一个类的实例化延迟到其子类。

Spring Bean 的创建是典型的工厂模式, 这一系列的 Bean 工厂, 也即 IOC 容器为开发者管理对象间的依赖关系提供了很多便利和基础服务, 在 Spring 中有许多的 IOC 容器的实现供用户选择和使用。

 

AOP面向切面编程

书面定义

AOP就好比一把刀,在程序运行的时候,可以随意的插入和拔出,在插入拔出的位置(切面)可以为所欲为,比如记录日志等。利用AOP可以实现对业务逻辑的各个部分进行分离,降低耦合度。

解析

就比如上图,当我们在手机银行APP进行取款、查询、转账的时候,都会先让你验证身份吧,我们可以把这个“验证身份”过程提取出来,即画一个类似“切面”的绿线。即在一系列纵向的控制流程中,把那些相同的子流程提取成一个横向的面

那么我们能不能把这个公共功能提取出来,包装一下呢?有了AOP之后,我们可以先把主要流程写完,然后反过来在另一个地方写验证身份的代码,然后告诉Spring要插入到哪些地方即可,而不需要你自己Copy过去。

AOP的主要思想是先实现程序的整体框架,然后再具体的编写每个部分的详细代码,最后插到整体框架里面


比如1个main函数调用了100个方法,现在要求在执行调用方法之前输出一句日志

最暴力的方法就是每个方法复制粘贴syso即可。

采用面向对象思想,就是编写一个日志打印方法,该方法执行这些日志打印操作,然后在每个业务方法之前加入这句方法调用

但是如果要求我们在业务方法结束时再打印一些日志呢,是不是还要去每个业务方法结束时加一遍?这样始终不是办法,而且我们总是在改业务方法,在业务方法里面掺杂了太多的其他操作,侵入性太高。这时候AOP就起到作用了,我们可以编写一个切面类(Aspect),在其中的方法中来编写横切逻辑(如打印日志),然后通过配置或者注解的方式来声明该横切逻辑起作用的位置,从而不需要改变原先代码即可实现所需要的功能。

 

实现方式

Spring AOP采用的是JDK动态代理,在运行期间对业务方法进行增强,所以不会生成新类。

 

参考网址列表:

参考网址1

参考网址2

参考网址3


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2天前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
30天前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
110 9
|
27天前
|
存储 Java 程序员
SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
本文详细讲解了Spring框架中IOC容器如何存储和取出Bean对象,包括五大类注解(@Controller、@Service、@Repository、@Component、@Configuration)和方法注解@Bean的用法,以及DI(依赖注入)的三种注入方式:属性注入、构造方法注入和Setter注入,并分析了它们的优缺点。
18 0
SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
|
27天前
|
存储 开发框架 Java
什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码
文章详细介绍了Spring、IOC、DI的概念和关系,解释了控制反转(IOC)和依赖注入(DI)的原理,并提供了IOC的代码示例,阐述了Spring框架作为IOC容器的应用。
20 0
什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码
|
14天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
43 0
|
22天前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
37 0
|
2月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
57 1
|
3天前
|
XML Java 开发者
论面向方面的编程技术及其应用(AOP)
【11月更文挑战第2天】随着软件系统的规模和复杂度不断增加,传统的面向过程编程和面向对象编程(OOP)在应对横切关注点(如日志记录、事务管理、安全性检查等)时显得力不从心。面向方面的编程(Aspect-Oriented Programming,简称AOP)作为一种新的编程范式,通过将横切关注点与业务逻辑分离,提高了代码的可维护性、可重用性和可读性。本文首先概述了AOP的基本概念和技术原理,然后结合一个实际项目,详细阐述了在项目实践中使用AOP技术开发的具体步骤,最后分析了使用AOP的原因、开发过程中存在的问题及所使用的技术带来的实际应用效果。
16 5
|
21天前
|
Java 容器
AOP面向切面编程
AOP面向切面编程
37 0
|
2月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
【9月更文挑战第9天】AOP(面向切面编程)通过分离横切关注点提高模块化程度,如日志记录、事务管理等。Micronaut AOP基于动态代理机制,在应用启动时为带有特定注解的类生成代理对象,实现在运行时拦截方法调用并执行额外逻辑。通过简单示例展示了如何在不修改 `CalculatorService` 类的情况下记录 `add` 方法的参数和结果,仅需添加 `@Loggable` 注解即可。这不仅提高了代码的可维护性和可扩展性,还降低了引入新错误的风险。
44 13