Spring学习前置知识

Spring作用

Spring是一个轻量级的开源框架,是为解决企业级应用开发的复杂性而创建的,通过核心的Bean Factory实现了底层类的实例化和生命周期的管理;
Spring的根本使命:简化Java开发

OCP开闭原则

开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开闭原则正是这一目标的直接体现,其他的设计原则,很多时候都是未实现这一目标服务的
开:对扩展开放 闭:对修改关闭
开闭原则的核心思想是对系统的抽象进行编程,通过定义抽象接口或者抽象类,使得系统具有一定的灵活性和扩展性。在需要修改系统的功能时,可以通过添加新的实现类或者子类来扩展系统的功能,而不是直接修改已有的实现类或者基类,从而降低代码的耦合性,提高代码的可维护性和可扩展性。
开闭原则的优点包括:
a. 可扩展性:通过添加新的代码或者类,可以扩展系统的功能,满足不同的需求。
b. 可维护性:不需要修改已有的代码,减少了代码的修改次数和维护成本。
c. 可复用性:通过抽象化和接口编程,可以提高代码的复用性。
d. 可测试性:由于代码的耦合性降低,可以更容易地进行单元测试和集成测试。

也就是说,如果在进行功能扩展的时候,添加额外的类是没问题的,但因为功能扩展而修改之前运行正常的程序,这是忌讳的,不被允许的。因为一旦修改之前运行正常的程序,就会导致项目整体要进行全方位的重新测试。这是相当麻烦的过程。导致以上问题的主要原因是:代码和代码之间的耦合度太高。如下图所示:

可以明显的看出,上层依赖下层的。UserController依赖UserServiceImpl,而UserServiceImpl依赖UserDaoImplForMySql,这样就会导致下面只要改动,上面必然会受牵连(跟着也会改动),所谓牵一发而动全身。这样也就违背了另一个开发原则:依赖倒置原则。

依赖倒置原则DIP

依赖导致原则(Dependency Inversion Principle, DIP)的定义总结为:
高层模块不应该依赖于底层模块,两者都应该依赖于抽象
抽象不应该依赖于细节,细节应该依赖于抽象
依赖倒置原则的核心思想就是通过抽象接口和依赖倒置来实现代码的松耦合,降低模块之间的依赖性,提高代码的可维护性、可扩展性和可复用性。
依赖倒置原则的实现方式包括:
(一) 抽象接口:定义抽象接口,将高层模块和底层模块解耦,使得它们只依赖于抽象接口而不依赖于具体实现
(二)接口隔离原则:定义多个专门的接口,而不是一个大而全的接口,避免出现不必要的依赖关系
(三)依赖注入:通过依赖注入(Dependency Injection)的方式,将依赖关系从高层模块中抽离,交由外部容器或者框架注入
(四)依赖查找:通过依赖查找(Dependency Look)的方式,使得高层模块可以从容器或者框架中查找需要的底层模块,实现模块之间的解耦
2.1 核心:倡导面向接口编程、面向抽象编程,不要面向具体编程
2.2 目的:降低程序的耦合性,提高扩展力
控制反转IOC
控制反转(Inversion of Control, IoC)是一种设计模式,它是面向对象编程中依赖倒置原则的一种实现方式。控制反转是指将程序的控制权由程序员转移给框架或者容器,由它来控制对象的创建、销毁、依赖关系的维护等操作。在传统的程序开发过程中,程序员自己负责对象的创建和维护,导致代码的耦合度较高,而控制反转则可以解决这个问题,它将通过将对象的创建和维护交给框架或容器来实现代码的耦合。
控制反转的核心思想是通过定义抽象接口和依赖注入来实现代码的松耦合,它包括以下几个步骤:

  1. 定义抽象接口:定义抽象接口,描述对象的行为和功能,由程序员来编写
  2. 实现具体类:实现抽象接口的具体类,由框架或容器来创建和维护,由程序员配置
  3. 注册对象:将具体类注册到容器中,告诉容器哪些对象需要创建和维护
  4. 依赖注入:将对象的依赖关系交给容器来维护,容器在创建对象时,自动将对象所需要的依赖注入到对象中,避免程序员手动维护依赖关系。
    控制反转常见的实现方式:依赖注入
    控制反转是一种思想,依赖注入是这种思想的具体实现,常见方式:
    第一种: set注入 (执行set方法给属性赋值)
    第二种:构造方法注入 (执行构造方法给属性赋值)
    依赖注入 中 “依赖”是什么意思?“注入”是什么意思?
    ● 依赖:A对象和B对象的关系
    ● 注入:是一种手段,通过这种手段,可以让A对象和B对象产生关系
    ● 依赖注入:对象A和对象B之间的关系,靠注入的手段来维护,而注入的方法包括:set注入和构造方法注入
    控制反转是一种新型的设计模式,但是因为比较新,没有被纳入GOF 23种设计模式中

优质程序代码的书写原则

程序的耦合和内聚

耦合与内聚的介绍:
内聚:内聚指的是一个模块(类或者函数等)内部各个元素(方法、属性等)之间关联的紧密程度。高内聚意味着各个元素都紧密相关。共同为为实现一个单一、清晰、定义良好的目标而努力。这样的模块更易于理解、维护和复用。

高内聚的例子:一个类只负责处理用户信息的验证,包括用户名、密码、邮箱等的验证逻辑。这个类中所有的方法、变量都是紧密围绕着用户信息验证这一主题。
○ 低内聚的例子:一个模块中既有添加数据的逻辑,又有更新数据的逻辑,还可能有其他不相关的功能,这样的模块就显得杂乱无章,内聚度低。
耦合:耦合指的是不同模块之间相互依赖的程度。每个模块都可以独立地修改/新增而不修改其他的模块。 ○
低耦合的例子:两个模块通过定义良好的接口进行通信,一个模块的改变不会影响到另一个模块,除非接口本身发生变化。 ○
高耦合的例子:一个模块直接访问另一个模块的内部数据或方法,或者两个模块之间存在复杂的、难以理解的依赖关系。 耦合与内聚的关系
耦合与内聚在定义上是独立的,但它们之间存在着一种微妙的关系,一般来说,追求高内聚的同时,也倾向于实现低耦合。因为高耦合的模块通常具有清晰的职责边界,这样有助于减少模块间的依赖,从而降低耦合度。
在通常情况下,我们会努力在两者之间找到一个平衡点,为了提高系统的整体性能或满足特定的设计需求,可能会在一定程度上牺牲内聚或耦合,以实现既易于维护又高效的系统。

内聚代码演示

//反例: 一个方法内实现了太多的计算功能,不符合高内聚思想 弊端:不方便维护,扩展性差
public int compute(int i, int j, String label){if ("+".equals(label)){return i + j;}else if ("-".equals(label)){return i - j;}else{// do something}return 0;
}-----------------------------------------------------------------------------------
//高内聚例子: 好处:扩展性好 开闭原则:向扩展开发,向修改闭合
public int add(int i, int j){return i + j;
}public int sub(int i, int j){return i - j;
}

耦合代码演示
MVC三层架构演示

public interface UserDao {void add();void update();
}public class UserDapImpl implements UserDao{@Overridepublic void add() {System.out.println("Mysql数据库正在新增用户....");}@Overridepublic void update() {System.out.println("Mysql数据库正在修改用户....");}
}
public interface UserService {void add();void update();
}public class UserServiceImpl implements UserService{@Overridepublic void add() {// UserServiceImpl 依赖于UserDapImpl,如果UserDapImpl的add方法变更,那么这里也需要变更,我们称之为耦合度高UserDao userDao = new UserDapImpl();userDao.add();}@Overridepublic void update() {}
}

耦合的弊端

耦合弊端说明
维护成本高以UserService调用UserDao为例,如果DAO实现方案修改,则需要做硬编码调整,维护性差;
独立性差以UserService调用UserDao为例,UserService下功能脱离UserDao无法独立实现功能;
可复用性不高因为模块间存在耦合,导致很难被有效引用;比如:B与C耦合,而A仅仅想引用B,但实际情况是A间接与C也耦合了,说明B的复用性较差;

工厂模式解耦

【1】原始方案
服务层与持久层存在耦合,一旦替换持久层实现方案,则需要硬编码修改代码,维护性很差;

【2】工厂模式降低耦合
思考:服务层与持久层存在耦合,说白了就是在服务层直接创建持久层对象,存在强引用,也就是紧耦合,如何解决?
我们可以把创建持久层对象的功能封装到一个工具类下,也就是说这个工具类专门用来创建持久层对象,将来方案修改,也仅仅修改工具类即可,这也就是工厂模式的雏形;

工厂模式解耦代码实例

public class DaoFactory {/*** UserDao 工厂对象实例化方法*/public static UserDao UserDaoGetInstance(){// 解决ServiceImpl和Dao的耦合问题:这里引用UserDao的实现类// 但是出现新的耦合问题:工厂与创建对象的耦合return new UserDaoImpl2();}
}public class UserServiceImpl implements UserService{@Overridepublic void update() {// 调用工厂类,这样UserServiceImpl与UserDao就没有了直接依赖关系,完成解耦UserDao userDao = DaoFactory.UserDaoGetInstance();userDao.update();}
}

引入工厂模式的好处与弊端:

[1] 好处:当持久层或者服务层方案修改时,仅仅修改工厂类即可完成实现方案的切换,维护性相对较好。 [2]
弊端:加入工厂模式后,服务层与持久层完成解耦,但是又引入了新的耦合,即工厂类与持久层存在紧耦合。

Spring雏形(基于工厂模式)

工厂模式的思考
Spring是基于工厂模式创建的
工厂类与工厂生产的对象之间如何实现的解耦:

a. 将工厂生产的对象类信息配置到静态文件中
b. 工厂类通过I/O加载静态资源,获取配置信息,然后通过反射创建对象
好处:将工厂创建的对象静态配置化,这样即使对象实现方案进行了切换,也仅仅修改静态文件,无需修改工厂代码

最终解决方案:工厂 + 静态配置文件 + 反射
在Spring中工厂维护的对象称为 Bean。

工厂模式Bean实现

创建Bean.properties配置文件,其中key为使用时的参数,value是需要引用的实现类的全限定类名,之所以要全限定类名,是因为在反射创建对象的时候需要使用到。

userDao=com.powernode.Dao.UserDaoImpl
UserService=com.powernode.Service.UserServiceImpl

工厂模式Bean多例模式实现

定义

package com.powernode.factory;import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;/*** @Author: * @Description: 工厂 + 静态配置 + 反射*              定义创建对象的工厂,实现bean多实例创建* @DateTime: 2024/9/19 18:54*/
public class BeanFactory {// 专门存放bean的定义对象private static Map<String, String> beanInformation = new HashMap<>();// 使用静态代码块,实现Bean.properties文件资源 io只需要走一次static {// 1、读取配置文件ResourceBundle bundle = ResourceBundle.getBundle("Bean");// 2、获取配置文件中的keyEnumeration<String> keys = bundle.getKeys();// 3、循环将对象信息以Map的形式存储while (keys.hasMoreElements()){String key = keys.nextElement();String className = bundle.getString(key);beanInformation.put(key, className);}}// 获取bean对象public static Object getBean(String beanName) {// 1、通过beanName获取到配置文件中内容String className = beanInformation.get(beanName); // 全限定类名Object bean = null;// 2、通过反射 根据全限定类名创建对象try{Class<?> aClass = Class.forName(className);bean = aClass.newInstance();}catch (Exception e){e.printStackTrace();System.out.println("获取bean失败");}// 3、返回Beanreturn bean;}
}

使用

package com.powernode.Service;import com.powernode.Dao.UserDao;
import com.powernode.Dao.UserDaoImpl;
import com.powernode.factory.BeanFactory;
import com.powernode.factory.BeanSingletonFactory;/*** @Author: * @Description: TODO* @DateTime: 2024/9/19 15:19*/
public class UserServiceImpl implements UserService{UserDao userDao = (UserDao) BeanFactory.getBean("userDao");@Overridepublic void add() {UserDao userDao = (UserDao) BeanFactory.getBean("userDao");System.out.println("add:userDao:" + userDao);userDao.add();}@Overridepublic void update() {UserDao userDao = (UserDao) BeanFactory.getBean("userDao");System.out.println("update:userDao:" + userDao);userDao.update();}
}public class Main {public static void main(String[] args) {UserService userService = (UserService) BeanFactory.getBean("UserService");userService.add();userService.update();}
}

运行效果

add:userDao:com.powernode.Dao.UserDaoImpl@573f2bb1
Mysql数据库正在新增用户....
update:userDao:com.powernode.Dao.UserDaoImpl@5ae9a829
Mysql数据库正在修改用户....

工厂模式Bean单例模式实现

定义

package com.powernode.factory;import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;/*** @Author: * @Description: 工厂 + 静态配置 + 文件 生成Bean*              一个key只能对应一个对象 单例模式* @DateTime: 2024/9/19 19:15*/
public class BeanSingletonFactory {// 定义Bean信息private static Map<String, String> beanInformation = new HashMap<>();// 定义存储实例化Bean的Mapprivate static Map<String, Object> singletonBean = new HashMap<>();// 读取配置文件static {ResourceBundle bundle = ResourceBundle.getBundle("Bean");Enumeration<String> keys = bundle.getKeys();while (keys.hasMoreElements()){String key = keys.nextElement();String className = bundle.getString(key);beanInformation.put(key, className);}}// 获取Beanpublic static Object getBean(String className){// 1、先从集合中获取beanObject bean = singletonBean.get(className);//2、如果bean集合中不存在则重新创建if (bean == null){String info = beanInformation.get(className);try {Class<?> aClass = Class.forName(info);bean = aClass.newInstance();// 将bean保存到Bean集合中,方便下次直接获取singletonBean.put(className, bean);}catch (Exception e){e.printStackTrace();System.out.println("获取bean失败");}}return bean;}
}

使用

package com.powernode.Service;import com.powernode.Dao.UserDao;
import com.powernode.Dao.UserDaoImpl;
import com.powernode.factory.BeanFactory;
import com.powernode.factory.BeanSingletonFactory;/*** @Author: * @Description: TODO* @DateTime: 2024/9/19 15:19*/
public class UserServiceImpl implements UserService{@Overridepublic void add() {UserDao userDao2 = (UserDao) BeanSingletonFactory.getBean("userDao");System.out.println("add:userDao:" + userDao2);userDao2.add();}@Overridepublic void update() {UserDao userDao2 = (UserDao) BeanSingletonFactory.getBean("userDao");System.out.println("update:userDao:" + userDao2);userDao2.update();}
}public class Main {public static void main(String[] args) {UserService userService = (UserService) BeanFactory.getBean("UserService");userService.add();userService.update();}
}

可以从最终的运行效果可以看到,虽然都调用了getBean方法,但是对象其实并没有改变
运行效果

add:userDao:com.powernode.Dao.UserDaoImpl@573f2bb1
Mysql数据库正在新增用户....
update:userDao:com.powernode.Dao.UserDaoImpl@573f2bb1
Mysql数据库正在修改用户....

Spring的发展历程

工厂模式+静态配置+反射: 最终没有消除耦合,只是降低了耦合 静态配置文件与资源的耦合依旧存在;
静态配置文件修改后无需重复编译,耦合降到最低; 程序间的耦合是无法彻底消除的,只能尽可能的降低耦合。

详情跳转:参考

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

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

相关文章

2.计算机网络基础

2. 计算机网络基础 (1) 计算机网络的定义 计算机网络是指将地理位置不同、具有独立功能的多个计算机系统通过通信线路和设备连接起来,以功能完善的网络软件实现网络中资源共享的系统。最简单的定义是:计算机网络是一些互相连接的、自治的计算机系统的集合。最庞大的计算机网…

在 PostGIS 中进行千万级空间数据的空间查询和关键字查询

一、目的 本测试在探究在有限的计算机配置下&#xff0c;如何高效地对千万级的空间数据进行空间查询和关键字查询。通过实际操作和测试&#xff0c;评估不同查询策略的性能&#xff0c;为处理大规模空间数据提供可行的解决方案。 计算机配置如下&#xff1a; 内存&#xff0…

声网SDK脚本运行错误

文章目录 运行步骤无法运行.bat电脑出现警告--更改执行策略若无出现-更新power shell搜索最新版本的 PowerShell安装新版本 仍无法解决-手动下载第三方库 2024-9-9运行步骤 无法运行.bat 电脑出现警告–更改执行策略 若无出现-更新power shell 搜索最新版本的 PowerShell 在…

记录|如何对批量型的pictureBox组件进行批量Image设置

目录 前言一、问题表述二、批量化处理更新时间 前言 参考文章&#xff1a; 一、问题表述 问题就是上图所示&#xff0c;这些的命名风格统一&#xff0c;只是最后的数字是不同的。所以存在可以批量化进行处理的可能性。 二、批量化处理 private void SetPictureBoxImages(){for…

ElementPlus表单验证报错 formEl.validate is not a function

出现问题的代码 <!-- 密码重置弹框 --><el-dialog v-model"innerVisible" width"500" title"密码重置" append-to-body><el-form ref"ruleFormRef" style"max-width: 600px" :model"passForm" sta…

HarmonyOS元服务与卡片

元服务与卡片 文章目录 一、元服务1.介绍2.常见元服务项目步骤 二、卡片1.介绍2.卡片的创建3.卡片的数据的变更4.卡片的进程间通讯4.1使用工具包4.2使用步骤 5.卡片路由postCardAction&#xff1a;快速拉起后台5.1格式5.2快速拉起指定页面--router5.3调用后台功能--call5.3卡片…

委托的注册和注销

让我们来回顾一下委托的内容。 委托 是一种复杂的数据类型&#xff0c;需要我们先定义出来。当定义好类型后&#xff0c;声明委托变量来使用。 可以装载方法&#xff0c;只可以装载具有相同返回类型和参数列表的方法。 委托变量名&#xff08;参数列表&#xff09;&#xf…

使用Webpack创建vue脚手架并搭建路由---详解

1.使用 vue 库 vue 是一个非常好用的 javascript 库&#xff0c;现在已经发行了 vue 3&#xff0c;我们可以直接导入使用库文件&#xff0c;也可以使用单文件&#xff08;SFC&#xff09;的形式&#xff0c;直接使用库文件会简单一点&#xff0c;我们先来试一下吧。 1.1安装 v…

Qt 模型视图(二):模型类QAbstractItemModel

文章目录 Qt 模型视图(二)&#xff1a;模型类QAbstractItemModel1.基本概念1.1.模型的基本结构1.2.模型索引1.3.行号和列号1.4.父项1.5.项的角色1.6.总结 Qt 模型视图(二)&#xff1a;模型类QAbstractItemModel ​ 模型/视图结构是一种将数据存储和界面展示分离的编程方法。模…

巡检管理系统软件:功能与逻辑的深度探索

在现代企业管理中&#xff0c;巡检管理系统软件扮演着至关重要的角色。巡检管理系统不仅能提升巡检工作的效率和准确性&#xff0c;还能为企业的整体运营提供有力支持。下面将从功能与逻辑两个方面对巡检管理系统软件进行深入分析。 一、巡检管理系统软件的功能 巡检计划制定 …

快速体验Linux发行版:DistroSea详解与操作指南

DistroSea 是一个功能强大的在线平台&#xff0c;允许用户在无需下载或安装的情况下&#xff0c;通过浏览器直接测试多种Linux和BSD发行版。该平台非常适合Linux爱好者、系统管理员和开发者&#xff0c;提供一个简便的方式来体验各种操作系统而无需影响本地设备。 为什么选择D…

CleanMyMac 5 for Mac 最新中文破解版下载 系统优化垃圾清理工具

今天给大家带来的是CleanMyMac最新款CleanMyMac 5&#xff0c;它是一个全面的Mac清理和维护工具&#xff0c;通过提供多项强大的功能&#xff0c;帮助用户简化日常维护任务&#xff0c;提升系统性能&#xff0c;同时保护个人隐私和安全。无论是新手还是经验丰富的Mac用户&#…

如何实现实时监控局域网计算机桌面?学会这5个妙招你就能搞定!

在现代企业环境中&#xff0c;实时监控局域网内的计算机桌面已成为确保工作效率、维护信息安全的重要手段。 无论是出于管理需求还是安全考虑&#xff0c;掌握这一技能对于IT管理员来说都至关重要。 本文将详细介绍五个妙招&#xff0c;帮助你轻松实现局域网内计算机桌面的实…

python 自动化测试接口

比如我们要测试接口&#xff1a;identity/chatRecords/pages 已在Postman中有&#xff0c;那我们就可以直接从里面复制出Python脚本 新建&#xff1a; pagerequest.py import requests import jsonurl "http://192.168.31.132:70/identity/chatRecords/pages"payl…

gin配置swagger文档

一、基本准备工作 1、安装依赖包 go get -u github.com/swaggo/swag/cmd/swag go get -u github.com/swaggo/gin-swagger go get -u github.com/swaggo/files2、在根目录上配置swagger的路由文件 //2.初始化路由router : initialize.Routers()// 配置swaggerdocs.SwaggerInfo…

【网络安全】-ssrf服务器请求伪造攻击-burp

SSRF攻击服务器请求伪造攻击 CSRF攻击跨站请求伪造攻击也称客户端请求伪造攻击 两种攻击最主要的区别是一个在服务器&#xff0c;一个在客户端。 文章目录 前言 什么是SSRF攻击? 1.分类&#xff1a; 针对服务器的 SSRF 攻击&#xff1a; 针对后端系统的SSRF攻击&#xff1a; …

一篇文章解决ComfyUI常见的故障报错!

前言 学习和使用ComfyUI最痛苦的是什么&#xff1f;就是这满屏的红色方框和和[报错信息] “报错信息”)&#xff0c;处理完一批又一批&#xff0c;很多人玩了一两个流程就搞不下去了&#xff0c;很多初学者因此就放弃了。 有道是&#xff1a;配置流程大半天&#xff0c;跑通出…

【Python机器学习】NLP信息提取——值得提取的信息

目录 提取GPS信息 提取日期 如下一些关键的定量信息值得“手写”正则表达式&#xff1a; GPS位置&#xff1b;日期&#xff1b;价格&#xff1b;数字。 和上述可以通过正则表达式轻松捕获的信息相比&#xff0c;其他一些重要的自然语言信息需要更复杂的模式&#xff1a; 问…

【win工具】win安装flameshot并设置截图快捷键

1.下载flameshot软件2.windows端配置flameshot快捷键3.取消win自带截图快捷键 1.下载flameshot软件 https://flameshot.org/#download installer版本为安装包 portable版本为免安装版 2.windows端配置flameshot快捷键 https://cloud.tencent.com/developer/article/2114952 W…

Linux 防火墙:iptables (二)

文章目录 SNAT 原理与应用SNAT 应用环境SNAT 原理SNAT 转换前提条件SNAT 格式SNAT 转换规则配置 DNAT 原理与应用DNAT 应用环境DNAT 原理DNAT 转换前提条件DNAT 格式DNAT 转换规则配置 iptables 规则的备份和还原导出&#xff08;备份&#xff09;所有表的规则导入&#xff08;…