Spring后端框架复习总结

news2024/9/17 7:09:52

之前写的博客太杂,最近想把后端框架的知识点再系统的过一遍,主要是Spring Boot和Mybatis相关,带着自己的理解使用简短的话把一些问题总结一下,尤其是开发中和面试中的高频问题,基础知识点可以参考之前写java后端专栏,这篇不再赘述。

目录

  • Spring
    • 什么是AOP?底层原理?
    • 事务底层原理?多线程事务能不能保证一致性?
    • 为什么禁用@Transactional?
    • 事务失效场景?
    • Bean的生命周期及常用自定义方法
    • 有两个相同id的Bean会报错吗?
    • 循环依赖相关
    • Spring MVC是什么,核心是什么,它的执行流程?
    • Spring MVC的控制器(bean)是不是单例模式(是不是线程安全)?存在什么问题?如何解决?
    • 起步依赖、自动配置原理;yml等配置文件的配置优先级
    • IOC的工作流程;控制反转与依赖注入原理
    • 常见注解有哪些? @Autowird 与 @Resource区别;@Component和@Bean区别;@Conditional作用
    • 过滤器与拦截器的区别
    • 如何解决跨域问题?
    • 设计模式
  • Mybaits
    • MyBatis执行流程
    • Mybatis是否支持延迟加载?底层原理是什么?
    • 一级、二级缓存;二级缓存什么时候会清理缓存中的数据
    • Mybatis实现分页查询的几种方式

Spring

什么是AOP?底层原理?

详细介绍–>SpringBoot 事务与AOP

什么是AOP?

aop是面向切面编程,在spring中用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取公共模块复用,降低耦合,一般比如可以做为公共日志保存,事务处理等

我们当时在后台系统中,就是使用aop来记录了系统的操作日志。主要思路是这样的,使用aop中的环绕通知+切点表达式,这个表达式就是要找到要记录日志的方法,然后通过环绕通知的参数获取请求方法的参数,比如类信息、方法信息、注解、请求方式等,获取到这些参数以后,保存到数
据库。

AOP的底层原理?

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。

  • JDK动态代理只提供接口的代理,不支持类的代理
    • JDK会在运行时为目标类生成一个动态代理类$proxy*.class .
    • 该代理类是实现了接目标类接口,并且代理类会实现接口所有的方法增强代码
    • 调用时先去调用处理类进行增强,再通过反射的方式进行调用目标方法。从而实现AOP

  • 如果代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
    • CGLIB的底层是通过ASM(一种用于直接生成或修改字节码的框架,全称为 “Abstract Syntax Notation One”)在运行时动态的生成目标类的一个子类。(还有其他相关类)会生成多个。并且会重写父类所有的方法增强代码,
    • 调用时先通过代理类进行增强,再直接调用父类对应的方法进行调用目标方法。从而实现AOP。
      • CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
      • CGLIB除了生成目标子类代理类,还有一个FastClass(路由类),可以(但不是必须))让本类方法调用进行增强,而不会像jdk代理那样本类方法调用增强会失效

  • jck动态代理生成类速度快,调用慢,cglib生成类速度慢,但后续调用快。就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。


事务底层原理?多线程事务能不能保证一致性?

详细介绍–>SpringBoot 事务与AOP

spring实现的事务本质就是AOP完成,对方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后根据执行情况提交或者回滚事务。其中AOP底层是基于JDK动态代理和cglib动态代理实现的,这个上面有介绍。

Spring多线程事务能不能保证一致性

假设A方法被声明了@Transactional,然后在A方法里new一个线程,去执行B方法,那么这种情况下A和B能保证原子性或者数据一致性么?A失败了B会回滚吗?或者B失败了A会回滚吗?

答案:不能。因为Spring底层是使用ThreadLocal来保存事务信息的比如数据库连接Connection,所以一个线程永远只能有一个事务,Spring的事务是无法实现事务一致性的。
解决办法:可以自己解决,比如通过编程式的事务,自己控制提交和回滚,或者说通过分布式事务的思路,2PC,3PC,SAGA,MQ的消息最终一致性都可以解决。


编程式事务:这种方式是通过编程的方式来控制事务的提交和回滚。在Spring中,可以使用TransactionTemplate或者PlatformTransactionManager来实现。例如,你可以在A方法中创建一个新的事务,然后在B方法中使用相同的事务。如果A或B中有任何异常,你可以捕获这个异常并决定是否回滚事务。这种方式需要你手动管理事务,包括开始事务、提交事务、回滚事务等。


分布式事务:这是一种更复杂的解决方案,通常用于处理跨多个数据库或服务的事务。这种方法包括以下几种策略:
2PC(两阶段提交):这是一种原子性协议,它保证了所有参与者要么都提交事务,要么都不提交。它分为两个阶段:准备阶段和提交阶段。在准备阶段,所有参与者都会被询问是否可以提交事务,只有当所有参与者都同意提交事务时,才会进入提交阶段。否则,事务将被回滚。
3PC(三阶段提交):这是两阶段提交的改进版,它添加了一个超时机制,以防止在等待其他参与者响应时发生阻塞。
SAGA:这是一种长寿命事务的解决方案,它将一个大事务分解为多个小事务,每个小事务都可以独立地提交或回滚。如果某个小事务失败,SAGA会执行一系列的补偿操作来保证数据的一致性。
MQ(消息队列):这是一种最终一致性的解决方案,它使用消息队列来保证事务的一致性。如果A方法执行成功,它会发送一个消息到消息队列,然后B方法会监听这个消息队列,当它收到消息时,就会执行相应的操作。



为什么禁用@Transactional?

为什么有些公司禁止使用@Transactional声明式事务?

有几个方面的考虑:

1、在方法上面增加@Transactional的声明式事务,如果一个方法中存在较多耗时的操作,很容易引发长事务的问题,而长事务会带来锁的竞争,影响性能,同时也会导致数据库的连接池被消耗尽,影响程序正常执行

2、如果方法存在嵌套调用,而被嵌套调用的方法也声明了@Transactional事务,那么这个时候就会出现事务嵌套调用的行为,容易引起事务混乱,程序运行结果出现异常等问题

3、@Transactional的声明式事务是将事务控制逻辑放在注解里,如果项目复杂度增加,事务控制会变得更加复杂,导致代码的可读性和维护性下降,所以为了避免这类问题,有些公司会推荐使用编程式事务,这样可以更加灵活的去控制事务的范围,减少事务的锁定时间,提高系统性能



事务失效场景?

详细介绍–>SpringBoot 事务与AOP

Spirng通过@transactional注解来进行事务控制,但很多场景会导致事务失效。

第一个,如果方法上异常捕获处理,自己try catch处理了异常,没有抛出,就会导致事务失效,所以一般处理了异常以后,别忘了抛出去就行了

第二个,如果报RuntimeException以外的错也会导致事务失效,若在@Transactional上配置rollbackFor属性为Exception,这样别管是什么异常,都会回滚事务

默认情况下,只有出现RuntimeException(运行时异常)才会回滚事务。假如我们想让所有的异常都回滚,需要来配置@Transactional注解当中的rollbackFor属性,通过rollbackFor这个属性可以指定出现何种异常类型回滚事务

第三,如果方法是private修饰的,也会导致事务失效,因为AOP底层是基于cglib动态代理实现的,子类是不能重载父类的private方法的,所以无法很好的利用代理,会导致@Transactional失效。

ps:因为Spring事务是基于代理来实现的,所以某个加了@Transactional的方法只有是代理对象调用时,那么这个注解才会生效,所以如果是被代理对象来调用这个方法,那么@Transactional是不会生效的。

第四,@Transactional注解在了final或static修饰的方法上。因为被final修饰的方法是无法被重写的,所以代理对象是无法调用的。而static修饰的方法属于类对象不属于对象实例,所以代理对象也是无法调用的。

第五,当前类没有被Spring容器所管理,没有配置成bean。如果当前类没有被Spring 容器所管理,那么Spring就无法为该类生成代理对象,从而Spring 的事务会失效。

请添加图片描述

第六,同一个类中方法的调用,导致的 AOP失效,从而导致@Transactional注解失效。这也是我们开发中最容易犯错的一种场景。

请添加图片描述

同一个类中的方法调用,属于this 调用,并不会使用代理对象,所以 AOP会失效。没有办法通过动态代理给你进行增强。不过,该问题可以使用如下方式来解决,因为我们从spring容器中自动装配的bean假如实现了声明式事务或者AOP,那么就会为你创建动态代理。

请添加图片描述

除了上面的自动装配,还可以这样:((UserService)AopContext.currentProxy()).methodB()
也可以拿到当前的动态代理对象,这个方法的原理是当我们调用了一个动态代理的方法(methodA()),会把当前的动态代理对象存入到currentProxy的ThreadLocal中,那么此时再通过AopContext获得currentProxy,就可以拿到当前正在调用的动态代理对象,这种写法呢比自己注入进来更加优雅,且不会存在循环依赖问题。

第七,多个事务方法不在同一个线程内执行。如下代码片段中,事务方法addUser()中调用了另外一个事务方法roleService.addRole(),注意,这两个方法不是在同一个线程中执行的!这会导致什么问题呢?我们上面刚刚说过了,spring不能保证多线程下的事务一致性,这两个事务方法获取到的数据库连接是2个不同的数据库连接!不同的数据库连接会导致事务失效!解决办法在上面的Spring多线程事务能不能保证一致性中有介绍。

请添加图片描述

请添加图片描述



Bean的生命周期及常用自定义方法

详细介绍–>SpingBoot原理

在这里插入图片描述

简单来说分为五步:

  • 1.实例化:当容器需要初始化一个尚未初始化的Bean,或者初始化Bean时需要注入另一个尚未初始化的依赖时,容器会调用doCreateBean()方法进行实例化。实际上,这是通过反射的方式创建出一个Bean对象。
  • 2.属性赋值:Bean实例创建完成后,接下来是为这个Bean对象进行属性填充,也就是注入这个Bean依赖的其他Bean对象。
  • 3.初始化 :在属性填充完成后,进行Bean的初始化操作。初始化阶段包括以下几个步骤:
    • 3.1.执行Aware接口的方法:Spring会检测该对象是否实现了xxx Aware接口,通过Aware类型的接口,可以让我们获取Spring容器的一些资源。例如,实现BeanNameAware接口可以获取到Bean的名称,实现BeanFactoryAware接口可以获取到工厂对象BeanFactory等。
    • 3.2.判断Bean是否实现了InitializingBean接口,如果实现了,将会执行InitializingBean的afterPropertiesSet()初始化方法。
    • 3.3.执行用户自定义的初始化方法(如果有指定的话),如init-method等。
    • 3.4.执行BeanPostProcessor的后置处理方法postProcessAfterInitialization()。
  • 4.使用:初始化完成后,Bean就成功创建了,之后就可以使用这个Bean。
  • 5.销毁:当Bean不再需要时,会进行销毁操作。销毁阶段包括以下步骤:
    • 5.1.判断Bean是否实现了DestructionAwareBeanPostProcessor接口,如果实现了,则会执行DestructionAwareBeanPostProcessor后置处理器的销毁回调方法。
    • 5.2.判断Bean是否实现了DisposableBean接口,如果实现了,将会调用其实现的destroy()方法。
    • 5.3后判断这个Bean是否配置了destroy-method等自定义的销毁方法,如果有配置,则会自动调用其配置的销毁方法。

如果详细一点介绍的话可以分为五个阶段:

创建前准备:Bean在开始加载之前要从上下文和一些配置中去解析并且查找Bean有关

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

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

相关文章

[PM]产品运营

生命周期 运营阶段 主要工作 拉新 新用户的定义 冷启动 拉新方式 促活 用户活跃的原因 量化活跃度 运营社区化/内容化 留存 用户流失 培养用户习惯 用户挽回 变现 变现方式 付费模式 广告模式 数据变现 变现指标 传播 营销 认识营销 电商营销中心 拼团活动 1.需求整理 2.…

Linux中安装MySQL

1、新建目录用来存放MySQL安装包: mkdir upload、cd upload 2、输入命令下载MySQL安装包: wget https://cdn.mysql.com/archives/mysql-8.0/mysql-8.0.18-el7-x86_64.tar.gz 3、在系统中安装一系列软件包的: yum -y install wget cmake gcc g…

SonarQube执行代码扫描失败,Can not execute Findbugs

SonarQube 版本 9.2.4 SonarQube执行代码扫描失败,报错如下 remote: INFO: Sensor FindBugs Sensor [findbugs] remote: INFO: Findbugs plugin version: 4.2.6 remote: INFO: JavaResourceLocator.binaryDirs() not available before SonarQube …

【Vue】深入了解 v-for 指令:从基础到高级应用的全面指南

文章目录 一、v-for 指令概述二、v-for 指令的基本用法1. 遍历数组2. 遍历对象3. 使用索引 三、v-for 指令的高级用法1. 组件列表渲染2. 使用 key 提升性能3. 嵌套循环 四、结合其他功能的高级用法1. 处理过滤和排序后的结果2. 迭代数值范围3. 结合其他命令使用模板部分 (<t…

设计模式:使用最广泛的代理模式

需求场景 按着惯例&#xff0c;还是以一个应用场景作为代理模式的切入点。现在有一个订单系统&#xff0c;要求是:一旦订单被创建&#xff0c;只有订单的创建人才可以修改订单中的数据&#xff0c;其他人则不能修改。 基本实现思路 按着最直白的思路&#xff0c;就是查询数据…

数据结构小测试:排序算法

目录 1、请简述数据结构八大排序算法的思路。 2、常用排序算法手写 冒泡排序&#xff1a; 选择排序&#xff1a; 快速排序&#xff1a; 归并排序&#xff1a; 堆排序&#xff1a; 3、额外再加一个二分查找吧 1、请简述数据结构八大排序算法的思路。 冒泡排序&#xff…

golang开发环境搭建与踩坑记录

文章目录 一、安装下载1、go环境2、ide 二、基本使用1、运行2、结构体与方法函数指针3、闭包4、指针5、map6、接口7、异常 三、包管理1、go mod语法2、项目下载所有依赖 一、安装下载 1、go环境 下载地址&#xff1a;https://go.dev/dl/ 或者&#xff1a;https://golang.goog…

19.x86游戏实战-创建MFC动态链接库

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

向量数据库选择浅谈

初见大模型 作为新手接触大模型后&#xff0c;LLM模型、Embedding模型、rank模型、vector模型等等选择上可谓是一步一个坑&#xff0c;迷茫的走在迷茫的大路上。总之各种途径去选择合适的模型&#xff0c;今天了解下向量数据库选择依据。 借鉴前人 学习之前先看看大家都在关注…

基于java+springboot+vue实现的中小企业人事管理系统(文末源码+Lw)128

基于SpringBootVue的实现的中小企业人事管理系统&#xff08;源码数据库万字Lun文流程图ER图结构图ppt演示视频软件包&#xff09; 系统角色&#xff1a; 员工、管理员 系统功能&#xff1a; 管理员登录 进入中小企业人事管理系统可以查看首页、个人中心、员工管理、部门信息管…

arthas监控本地耗时代码(windows)

1、安装 curl -O https://arthas.aliyun.com/arthas-boot.jar 2、运行 java -jar arthas-boot.jar 3、选择监控的程序端口 运行后如下&#xff1a;第二个是我的后端程序&#xff0c;我选择2后回车 4、监控代码块 trace com.example.demo.service.impl.LoginServiceImp…

Docker 镜像使用和安装

​ 1、简介 Docker是一个开源的应用容器引擎&#xff1b;是一个轻量级容器技术&#xff1b; Docker支持将软件编译成一个镜像&#xff1b;然后在镜像中各种软件做好配置&#xff0c;将镜像发布出去&#xff0c;其他使用者可以直接使用这个镜像&#xff1b; 运行中的这个镜像…

Java面试八股之Redis怎么实现消息队列

Redis怎么实现消息队列 Redis实现消息队列主要依赖于其内置的数据结构&#xff0c;如List、Pub/Sub&#xff08;发布/订阅&#xff09;和Stream。下面将分别介绍这三种方式及其特点&#xff1a; 1. List实现消息队列 Redis的List是一个双向链表&#xff0c;支持快速的头部和…

【学术会议征稿】第六届信息与计算机前沿技术国际学术会议(ICFTIC 2024)

第六届信息与计算机前沿技术国际学术会议(ICFTIC 2024) 2024 6th International Conference on Frontier Technologies of Information and Computer 第六届信息与计算机前沿技术国际学术会议(ICFTIC 2024)将在中国青岛举行&#xff0c;会期是2024年11月8-10日&#xff0c;为…

Python面试宝典第15题:岛屿数量

题目 在二维网格地图上&#xff0c;1 表示陆地&#xff0c;0 表示水域。如果相邻的陆地可以水平或垂直连接&#xff0c;则它们属于同一块岛屿。请进行编码&#xff0c;统计地图上的岛屿数量。比如&#xff1a;下面的二维网格地图&#xff0c;其岛屿数量为3。 基础知识 解决这类…

Linux入门以及Linux文件编程学习

Linux学习必备 首先我们学习Linux必须安装一个虚拟机&#xff0c;我是跟着韦东山老师安装的&#xff0c;具体可以跟着视频操作&#xff0c;简单易懂&#xff1a;安装虚拟机 Linux入门最基本简单的指令 一、Vi的使用 Vi文件名 创建或者打开一个文件&#xff0c;进入默认命令行…

[论文笔记] pai-megatron-patch Qwen2-CT 长文本rope改yarn

更改: # Copyright (c) 2024 Alibaba PAI and Nvidia Megatron-LM Team. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License a…

Linux——多路复用之select

目录 前言 一、select的认识 二、select的接口 三、select的使用 四、select的优缺点 前言 在前面&#xff0c;我们学习了五种IO模型&#xff0c;对IO有了基本的认识&#xff0c;知道了select效率很高&#xff0c;可以等待多个文件描述符&#xff0c;那他是如何等待的呢&a…

JavaScript 获取 url(get)参数

https://andi.cn/page/621584.html

Gitee 使用教程1-SSH 公钥设置

一、生成 SSH 公钥 1、打开终端&#xff08;Windows PowerShell 或 Git Bash&#xff09;&#xff0c;通过命令 ssh-keygen 生成 SSH Key&#xff1a; ssh-keygen -t ed25519 -C "Gitee SSH Key" 随后摁三次回车键&#xff08;Enter&#xff09; 2、查看生成的 SSH…