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

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

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

这里我先解释一下黑马程序员里的这个案例,兄弟们看视频的可以跳过这节课: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.mzph.cn/web/14444.shtml

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

相关文章

【webrtc】m98:Call的创建及Call对音频接收处理

call中多個流共享相同的辅助组件 这几个是与外部共用的 线程传输send控制module 线程任务队列工厂call的辅助组件中各种统计以及接收测的cc是自己创建的 call自己的多个辅助组件是外部传递来的 call 创建多个接收流 这里用一个set 来保存所有指针,并没有要map的意思:

【因果推断从入门到精通二】随机实验3

目录 检验无因果效应假说 硬币投掷的特殊性何在&#xff1f; 检验无因果效应假说 无因果效应假说认为&#xff0c;有些人存活&#xff0c;有些人死亡&#xff0c;但接受mAb114治疗而不是ZMapp与此无关。在174例接受mAb14治疗的患者中&#xff0c;113/17464.9%存活了28天&…

Java入门基础学习笔记47——ArrayList

什么是集合呢&#xff1f; 集合是一种容器&#xff0c;用来装数据的&#xff0c;类似数组。 有数组&#xff0c;为什么还要学习集合呢&#xff1f; 数组定义完成并启动后&#xff0c;长度就固定了。 而集合是大小可变&#xff0c;开发中用的最多的。 集合的特点&#xff1a;大…

汇聚荣科技有限公司优点有哪些?

在当今快速发展的科技时代&#xff0c;企业之间的竞争愈发激烈。作为一家专注于科技创新与研发的公司&#xff0c;汇聚荣科技有限公司凭借其卓越的技术实力和创新能力&#xff0c;在业界树立了良好的口碑。那么&#xff0c;汇聚荣科技有限公司究竟有哪些优点呢?接下来&#xf…

C++利用TinyXML读取XML文件

TinyXML是什么&#xff1f; TinyXML是一个轻量级的C XML解析器&#xff0c;它提供了一种简单的方法来解析和操作XML文档。TinyXML被设计为易于使用和集成到C项目中&#xff0c;并且非常适合处理小型XML文件。 以下是TinyXML的一些主要特点和优点&#xff1a; 轻量级: T…

OSPF问题

.ospf 选路 域内 --- 1类&#xff0c;2类LSA 域间 --- 3类LSA 域外 --- 5类&#xff0c;7类LSA --- 根据开销值的计算规则不同&#xff0c;还分为类型1和类型2 ospf 防环机制 区域内防环&#xff1a;在同一OSPF区域内&#xff0c;所有路由器通过交换链路状态通告&#xff…

226.翻转二叉树

翻转一棵二叉树。 思路&#xff1a; 指针做交换 用递归&#xff08;前序or后序&#xff0c;中序不行&#xff09; 前序&#xff1a;中左右 遍历到“中”的时候&#xff0c;交换它的左右孩子 然后分别对它的左孩子和右孩子使用“交换函数”&#xff08;定义的&#xff09;&a…

【网络版本计算器的实现】

本章重点 理解应用层的作用, 初识HTTP协议理解传输层的作用, 深入理解TCP的各项特性和机制对整个TCP/IP协议有系统的理解对TCP/IP协议体系下的其他重要协议和技术有一定的了解学会使用一些分析网络问题的工具和方法 ⭐注意!! 注意!! 注意!! 本课是网络编程的理论基础.是一个服务…

【YOLOv5/v7改进系列】替换激活函数为SiLU、ReLU、LeakyReLU、FReLU、PReLU、Hardswish、Mish、ELU等

一、导言 激活函数在目标检测中的作用至关重要&#xff0c;它们主要服务于以下几个关键目的&#xff1a; 引入非线性&#xff1a;神经网络的基本构建块&#xff08;如卷积层、全连接层等&#xff09;本质上是线性变换&#xff0c;而激活函数通过引入非线性&#xff0c;使得网络…

保安维稳,四信以科技构筑高速公路安全智慧防线

近日&#xff0c;广东梅大高速发生严重塌方事故&#xff0c;造成了严重的人员伤亡和财产损失。这一事件在公众心中敲响了安全的警钟&#xff0c;再次引起了公众对于交通设施运营安全性的重点关注。 国务院安委会办公室和国家防灾减灾救灾委员会办公室等主管机构先后印发紧急通知…

Spring Security整合Gitee第三方登录

文章目录 学习链接环境准备1. 搭建基本web应用引入依赖ThirdApp启动类创建index页面application.yml配置访问测试 2. 引入security引入依赖ProjectConfig访问测试 第三方认证简介注册gitee客户端实现1引入依赖application.yml配置文件创建index.html页面启动类InfoControllerPr…

【数学建模】储药柜的设计

2014高教社杯全国大学生数学建模竞赛D题目 题目描述 储药柜的结构类似于书橱&#xff0c;通常由若干个横向隔板和竖向隔板将储药柜分割成若干个储药槽(如图1所示)。为保证药品分拣的准确率&#xff0c;防止发药错误&#xff0c;一个储药槽内只能摆放同一种药品。药品在储药槽…

docker搭建gitlab及默认密码修改及配置修改

推荐官方文档 https://docs.gitlab.com/17.0/ee/install/docker.html 我使用的是docker run的方式&#xff0c;官方文档后面有docker-compose、swarm、k8s的部署文档 版本说明 1&#xff1a;可以部署gitlab-ce社区版和gitlab-ee企业版&#xff0c;然后&#xff0c;鉴于是个人…

AIGC绘画设计基础-建筑设计应用

一、AI及AIGC 对于AI大家都不陌生&#xff0c;但是AIGC这个概念好多人其实不大清楚。“AI”是指人工智能技术本身&#xff0c;而“AIGC”是指基于人工智能技术而生成的内容。 生成式人工智能——AIGC&#xff08;Artificial Intelligence Generated Content&#xff09;&…

SpringFramework实战指南

二、SpringFramework实战指南 目录 一、技术体系结构 1.1 总体技术体系1.2 框架概念和理解 二、SpringFramework介绍 2.1 Spring 和 SpringFramework概念2.2 SpringFramework主要功能模块2.3 SpringFramework 主要优势 三、Spring IoC容器和核心概念 3.1 组件和组件管理概念3…

起底震网病毒的来龙去脉

2010年&#xff0c;震网病毒被发现&#xff0c;引起世界哗然&#xff0c;在后续的10年间&#xff0c;陆陆续续有更多关于该病毒的背景和细节曝光。今年&#xff0c;《以色列时报》和《荷兰日报》又披露了关于此事件的更多信息&#xff0c;基于这些信息&#xff0c;我们重新梳理…

优于InstantID!中山大学提出ConsistentID:可以仅使用单个图像根据文本提示生成不同的个性化ID图像

给定一些输入ID的图像&#xff0c;ConsistentID可以仅使用单个图像根据文本提示生成不同的个性化ID图像。效果看起来也是非常不错。 相关链接 Code:https://github.com/JackAILab/ConsistentID Paper&#xff1a;https://ssugarwh.github.io/consistentid.github.io/arXiv.pd…

计算机毕业设计 | springboot养老院管理系统 老人社区管理(附源码)

1&#xff0c;绪论 1.1 背景调研 养老院是集医疗、护理、康复、膳食、社工等服务服务于一体的综合行养老院&#xff0c;经过我们前期的调查&#xff0c;院方大部分工作采用手工操作方式,会带来工作效率过低&#xff0c;运营成本过大的问题。 院方可用合理的较少投入取得更好…

Python数据可视化(七)

绘制 3D 图形 到目前为止&#xff0c;我们一直在讨论有关 2D 图形的绘制方法和绘制技术。3D 图形也是数据可视化的 一个很重要的应用方面&#xff0c;我们接下来就重点讲解有关 3D 图形的实现方法。绘制 3D 图形通常需要导 入 mpl_toolkits 包中的 mplot3d 包的相关模块&#x…