后端之路第二站(正片)——SprintBoot之:分层解耦

news2024/10/5 19:19:47

很抽象,我自己也不好理解,仅作为一个前端转后端的个人理解

一、先解释一个案例,以这个案例来分析“三层架构”

这里我先解释一下黑马程序员里的这个案例,兄弟们看视频的可以跳过这节课:Day05-08. 请求响应-响应-案例_哔哩哔哩_bilibili 看我这里的解说就可以,因为他这里把前端的文件塞到后端这里弄,还要解析XML文件来获取数据,完全没必要,没有任何地方会这样做了,直接看我的解释过一遍就行

首先他把一个写了我们要的数据的XML引入到spring boot项目中,我们可以理解类似为前端有时会在一个js文件里写一堆数据用于测试、模拟后端数据的(但实际后端应该是连接数据库,数据是来源于数据库的

然后他的这个鬼XML文件里的数据里还不直接写明白“性别”是(男/女),而是写成(1/0),“职业”也是,非要写成(1/2/3),然后还得到获取数据的地方把(1/0)、(1/2/3)解析成(男/女)、(讲师/班主任/....),这不是脱裤子放屁,多此一举吗

于是,他又去请求页面,再解析获取到XML数据后,再去进行以上这些逻辑处理......我们暂且理解为vue里的<script></script>这部分的逻辑处理吧

最后再把这些数据发送请求

(我只是为了方便各位理解!!不是一个东西啊!!)

那么结合前端我们可以理解为有点类似“表单数据传送”,我们先获取表单的所有数据,然后进行逻辑处理:拆分出数据然后封装进一个对象,最后发送请求给后端

但是看看这一坨代码这么乱......

二、三层架构是啥

那么分析一下一坨代码,可以看出其实可以分成三大块:

【数据访问】:解析数据源,拿到数据

【逻辑处理】:把数据抽出来进行一些逻辑处理

【接收请求、响应数据】:把数据封装好给回前端

那么我们应该把这三块分开来写,这样的话,那一部分出问题可以直接找到这一部分查看问题

因此人们就规定应该分成这三块:

这三块要做的事:

  • Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。

  • Service:业务逻辑层。处理具体的业务逻辑。

  • Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。

那么这个三层架构的执行流程是:

1、前端发起的请求,由Controller层接收(Controller响应数据给前端)

2、Controller层调用Service层来进行逻辑处理(Service层处理完后,把处理结果返回给Controller层)

3、Serivce层调用Dao层(逻辑处理过程中需要用到的一些数据要从Dao层获取)

4、Dao层操作文件中的数据(Dao拿到的数据会返回给Service层)

好,那么与之相反的,我们开发人员写代码的流程是:(切记!不要去管这里代码写了什么,过一遍流程就行!!!这里的代码不值得去花时间学习)

1、在【请求处理类】同级目录下创建一个【dao】目录

2、然后在【dao】目录下创建一个代表该获取的数据的接口(java里的接口,不是请求数据的那个接口)

然后创建这个接口的实现类(连同包含实现类的文件夹目录一块),implements实现这个类,然后把获取数据、解析数据的内容放到这里实现

记得把数据return出去

3、然后同样的流程【创建service目录】——>【创建代表数据的接口】——>【然后创建(连文件夹包一起)实现这个接口的实现类】——>【记得先创建并调用Dao的实现类对象,因为现在数据在Dao那】——>【然后service的实现类的内容就是处理数据的逻辑】

4、最后,创建【controller】目录,把一个【请求处理类】放到【controller目录】——>【然后现在完整、处理好的数据源在service实现类】——>【在方法外面创建service的实现类对象】——>【然后方法里调用service实现类对象,拿到数据】——>【然后通过请求return出去,响应给前端】

总结就是:

开发视角:数据源从外部到Dao——>然后我们要用service获取Dao的数据,然后处理——>然后Controller最后获取service处理好的数据,响应回前端

前端视角:发送请求给到Controller——>Controller找service要——>service找Dao要

三、分层解耦

1、理解耦合是什么?

耦合问题

首先需要了解软件开发涉及到的两个概念:内聚和耦合。

  • 内聚:通俗讲就是各功能功能模块跟自身功能联系

比如【Controller】的功能是接受请求、实现请求接口、响应回前端,【service】的功能是处理数据、做逻辑处理,【Dao】功能就是解析数据

那么这三块分开,各自里面的内容是各自的功能实现,这就是【内聚高】,互不影响

那么如果不分开,这三个内容的代码全堆【Controller】那里,那么【Controller】本来功能只用实现请求、响应前端的,现在当黑奴,一人干几份活,这就是【内聚低

  • 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。

比如【Controller】接收到前端请求后,找数据需要通过调用【service】来获取数据,而【service】找数据也得靠调用【Dao】来获取数据,这种联系就叫【耦合

当他们是三个部门,当少了一方部门、或者其中一个部门要改名字啥的,会牵连到三个部门,这就是【耦合高

但是软件工程开发要求【内聚低耦合高

那么就要分层解耦

2、分层解耦是什么?

那么现在我们要解耦,该怎么办?

我们思考一下【Controller】调用的是什么?是【service的实现类】。

那么【Controller】调用的时候其实不管你是叫【service_A】还是【service_B】,只要是implement实现了【service】这个接口的实现类,【Controller】都需要

那么就可以有这么一个外部【容器】,他装有实现了【service】接口的【实现类】,当【Controller】需要的时候就去【容器】找有没有,有的话就拿去用

(我们理解为“华为公司”需要招聘员工,不管你是清华学子、还是北大学子,只要你是实现、集合了“985/211重本院校”的学生,他都要。那么我们就可以设一个“人才市场”,里面有各个[实现、集合了“985/211重本院校”的学生],华为公司需要谁,就去人才市场要)

这里还有几个概念要知道:

控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。(通俗理解给自己签订卖身契,卖到人口市场,随时被人交易)

依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。(通俗理解为买家跟人口市场绑定了,有符合要求的就自动买了)

IOC容器中创建、管理的对象,称之为:bean对象 (理解为人口市场的奴隶hh)

四、IOC控制反转 + DI注入依赖

1、首先先把【Controller】【service】【Dao】之间的联系删掉

(理解为华为公司取消了跟某些高校的强制合作,不要固定那几个高校推荐内推的学生,选择让人才市场给自己分配员工)

2、然后开始【控制反转】

给【service】和【Dao】加上容器注解【@Component】

加上它,就意味着要将当前类“交给”IOC容器管理,成为IOC容器里的一个bean对象

(可以理解为高材生把自己的简历投放到人才市场了,由人才市场保管自己的简历)

3、然后开始【依赖注入】

要将【Controller】绑定上【依赖注入】,加上注解【@Autowired】

加上【@Autowired】就意味着运行时,IOC容器会提供该类型的bean对象,并赋值给该变量

(理解为华为公司把自己的HR丢人才市场,任由HR发挥,只要符合要求就直接招进公司)

4、那如果要更换bean对象怎么办?

加入我有一个【service】实现类【A】,我现在不要用它了,我要改成【B】怎么办?

把【A】的【@Component】注释掉,在【B】上面加上【@Component】就行了......就这么简单

五、Bean另外的衍生注解

注解说明位置
@Component声明bean的基础注解不属于以下三类时,用此注解
@Controller @Component 的衍生注解标注在控制器类上
@Service@Component的衍生注解标注在业务类上
@Repository@Component的衍生注解

标注在数据访问类上

(由于与mybatis整合,用的少)

是啥个意思呢?

意思是【控制反转】有的时候不一定要用【@Component】,其实【Controller】、【Service】、【Dao】的【控制反转】可以分别用【@Controller】、【@Service】、【@Repository】来注解

然后因为其实【@Service】、【@Repository】的源代码里其实是包含了【@Component】的,所以用【@Service】、【@Repository】就等于用【@Component

但是spring boot的web开发里,【Controller】控制器不能用【Component】,不过它除了注解【@Controller】,我们之前讲过【@RestController】也包含了【@Controller】,所以用【@ReastController】就可以了

六、主包(主目录)外面的包的Bean对象扫描不到

问题:使用前面学习的四个注解声明的bean,一定会生效吗?

答案:不一定。(原因:bean想要生效,还需要被组件扫描,比如你主包外面的bean对象就不会生效)

那就要用到组件扫描:【@ComponentScan】

但是【@ComponentScan】并不是乱用的,首先回到我们的【启动类】

我们知道【@SpringBootApplication】是【启动类】注解,但其实他还是包含了【@ComponentScan】的组件扫描注解,它可以扫描【当前包以及其自包里的所有的Bean】

但是要是Bean在主包的外面怎么办?

那这是才只能手动写【@ComponentScan】来导入要扫描的“包(目录)”,并且还得带上原本当前这个“包(目录)”,因为会覆盖下面的【@SpringBootApplication】

具体语法是:

@ComponentScan( { "外部含Bean的那个包" , "当前包" } )

但其实不建议这样,一般情况推荐全部Bean都放到启动类的包下,方便全局扫描

七、DI注入依赖选择一个Bean来注入

我们前面说过,如果想要注入依赖的时候,容器里有两个符合条件的实现类,只选择其中一个的话,就把另一个实现类的【@Component】注释掉

但是如果我容器里有成千上万个符合条件的【实现类Bean】怎么办?难道我要全部一个一个去注释吗?

比如下面这个例子,我有两个都写了【@Sevice】(怕忘了,再提醒一下这个也等于@Component)的【service实现类Bean】

然后此时再运行时就会报错,因为超过两个同类型的实现类Bean

这是因为注入依赖里的注解【@Autowired】,它是根据类型来自动获取容器里所有的符合的实现类Bean的,那么容器里有两个就拿两个,有十个就拿十个,而一旦超过了一个Bean就会报错

那么解决办法有三个

1、(不太推荐)@Primary:在要希望生效的那个Bean上添加这个注解

2、(可以)@Qualifier:在要注入依赖的地方、@Autowired前面指定你要哪一个Bean

3、(非常推荐)@Resouce:直接在注入依赖的地方,去掉@Autowired,替换成这个并指定要哪个Bean

1、@Primary是在要希望生效的那个Bean上添加这个注解,不推荐是因为跟注释【@Component】其实是半斤八两的啊.......你还得去一个一个找到这个Bean,然后再Bean的代码里改

2、@Qualifier就是在要注入依赖的地方、@Autowired前面指定你要哪一个Bean,这样确实很方便,直接指明要谁,美中不足就是,我感觉跟@Autowired有点重复,两在一块总感觉有点多余

另外解释为什么【实现类EmpServiceA】在@Qualifier这要写成【empServiceA】,因为我前面懒,省略了讲:Bean对象的名字其实是【实现类】名字的首字母小写......而不是它原本的实现类的那个名字

3、@Resouce为甚推荐?因为它是直接在注入依赖的地方,去掉@Autowired,替换成@Resouce,并写上指定要哪个Bean的名字就行

为什么它可以直接不要【@Autowired】,因为【@Resouce】是根据名字来注入Bean的!!

另外【@Primary】跟【@Qualifier】是spring boot框架提供的,而【@Resouce】是Java的JDK提供的

ok,本爷的spring boot学习先告一段落,后面先学MySQL,然后等再学回spring boot的时候再更新博客

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

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

相关文章

U-Mail邮件系统反垃圾解决方案,彻底解决垃圾邮件

随着互联网的普及和电子邮件的广泛应用&#xff0c;垃圾邮件已成为一种严重的网络污染。首先&#xff0c;垃圾邮件占用了大量的网络带宽&#xff0c;导致正常邮件的传输受阻&#xff0c;严重影响了用户的使用体验。其次&#xff0c;垃圾邮件中的恶意链接和欺诈信息可能导致用户…

day34 贪心算法 455.分发饼干 376. 摆动序列

贪心算法理论基础 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 贪心一般解题步骤&#xff08;贪心无套路&#xff09;&#xff1a; 将问题分解为若干个子问题找出适合的贪心策略求解每一个子问题的最优解将局部最优解堆叠成全局最优解 455.分发饼干 …

go routing 之 gorilla/mux

1. 背景 继续学习 go 2. 关于 routing 的学习 上一篇 go 用的库是&#xff1a;net/http &#xff0c;这次我们使用官方的库 github.com/gorilla/mux 来实现 routing。 3. demo示例 package mainimport ("fmt""net/http""github.com/gorilla/mux&…

Python知识详解【1】~{正则表达式}

正则表达式是一种用于匹配字符串模式的文本工具&#xff0c;它由一系列普通字符和特殊字符组成&#xff0c;可以非常灵活地描述和处理字符串。以下是正则表达式的一些基本组成部分及其功能&#xff1a; 普通字符&#xff1a;大多数字母和数字在正则表达式中表示它们自己。例如…

深度学习之基于MTCNN+Facenet的人脸识别身份认证系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 随着信息技术的快速发展&#xff0c;身份认证技术在日常生活和工作中的重要性日益凸显。传统的…

初始MyBatis ,详细步骤运行第一个MyBatis程序,同时对应步骤MyBatis底层剖析

1. 初始MyBatis &#xff0c;详细步骤运行第一个MyBatis程序&#xff0c;同时对应步骤MyBatis底层剖析 文章目录 1. 初始MyBatis &#xff0c;详细步骤运行第一个MyBatis程序&#xff0c;同时对应步骤MyBatis底层剖析每博一文案2. 前沿知识2.1 框架&#xff08;framework&#…

Oracle递归查询笔记

目录 一、创建表结构和插入数据 二、查询所有子节点 三、查询所有父节点 四、查询指定节点的根节点 五、查询指定节点的递归路径 六、递归子类 七、递归父类 一、创建表结构和插入数据 CREATE TABLE "REGION" ( "ID" VARCHAR2(36) DEFAULT SYS_GUI…

jdk17安装教程详细(jdk17安装超详细图文)

2021年9月14日JDK17 发布&#xff0c;其中不仅包含很多新语言功能&#xff0c;而且与旧版 JDK 相比&#xff0c;性能提升也非常明显。与之前 LTS 版本的 JDK 8 和 JDK 11 相比&#xff0c;JDK17 的性能提升尤为明显&#xff0c;本文将教你如何安装 相比于JDK1.8&#xff0c;JD…

信号:MSK调制和GMSK调制

目录 一、MSK信号 1. MSK信号的第k个码元 2.MSK信号的频率间隔 3.MSK信号的相位连续性 3.1 相位路径 3.2初始相位ψk 4.MSK信号的产生 原理框图 5.MSK信号的频谱图 二、高斯最小频移键控(GMSK) 1.频率响应 2.GMSK调制产生方式 2.1 高斯滤波器法 2.2 正交调制器法…

《MySQL怎样运行的》—InnoDB数据页结构

在上一篇文章中我们讲了&#xff0c;InnoDB的数据页是InnoDB管理存储空间的基本单位&#xff0c;一个页的大小基本为16kb 那你有没有疑问&#xff0c;就是说这个InnoDB的数据页的结构是什么样的&#xff0c;还有他这些结构分别有那些功能~接下来我们一一讲解 数据页的总览结构…

内部类知识点

什么是内部类&#xff1f; 内部类何时出现&#xff1f;B类是A类的一部分&#xff0c;且B单独存在无意义 内部类分类 成员内部类&#xff1a; 当内部类被private修饰后&#xff0c;不能用方法2 调用外部类成员变量 内部类里面有隐藏的outer this来记录 静态内部类 创建对象&…

路由引入实验(华为)

思科设备参考&#xff1a;路由引入实验&#xff08;思科&#xff09; 技术简介 路由引入技术在网络通信中起着重要的作用&#xff0c;能够实现不同路由协议之间的路由传递&#xff0c;并在路由引入时部署路由控制&#xff0c;实现路径或策略的控制 实验目的 不同的路由协议之…

用Intellij实现web登录页面时,servlet已经配置好了,但是还是报404

今天看到一个404问题&#xff1a; 用Intellij实现web登录页面时&#xff0c;代码如下图所示。点击运行后会跳转到浏览器&#xff0c;但是输入/login时&#xff0c;浏览器显示404&#xff0c;且无法在控制面板上打印内容&#xff1b;输入/index时&#xff0c;也无法在浏览器上显…

html+css 驾考首页设计

效果 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>17sucai - A Pen by Mark Boots</title><!-- <link rel"stylesheet" href"./style.css"> --></head>…

【源码分享】简单的404 HTML页面示例,该页面在加载时会等待2秒钟,然后自动重定向到首页

展示效果 源码 html <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><title>404 页面未找到</title><meta http-equiv"refresh" content"2;url/"> <!-- 设置2秒后跳转到首…

[安洵杯 2019]crackMe

直接就退出程序了 找到关键函数了&#xff0c;好像用到了 hook 还有一个 嘿嘿&#xff0c;看着就是像 base64 只是 补‘’改成了‘ &#xff01; ’ 交叉引用啊&#xff0c;翻到一个应该是最后比较函数 1UTAOIkpyOSWGv/mOYFY4R!! 那一坨对 a1数组的操作没看懂 先总结一下就是…

Golang的基本使用

目录 变量的声明 Golang常用容器 defer 有趣的多态 结构体标签和reflect 反射 Golang最强的协程 channel go可能造成的内存泄露 变量的声明 方法 1:有类型,有var,不赋值 在Golang中默认值为0 方法 2:无类型,有var,赋值 方法 3:无类型,无var,赋值 多变量声明 多变…

C语言 数组——查找算法的函数实现

目录 线性查找&#xff08;Linear Search&#xff09; 线性查找的性能 猜数游戏 二分查找&#xff08;Binary Search&#xff09; 并非吹毛求疵&#xff0c;鸡蛋里挑骨头 二分查找的性能 线性查找&#xff08;Linear Search&#xff09; 不 要求数据表是已排好序的  …

AI巨头争相与Reddit合作:为何一个古老的论坛成为AI训练的“宝藏”?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…