Spring后端框架复习总结

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

目录

  • Spring
    • 什么是AOP?底层原理?
    • 事务底层原理?多线程事务能不能保证一致性?
    • 事务失效场景?
    • 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方法会监听这个消息队列,当它收到消息时,就会执行相应的操作。



事务失效场景?

详细介绍–>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有关扩展的实现,比如像init-method,容器在初始化Bean的时候或调用的一个方法,destroy-method,容器在销毁Bean的时候会调用的一些方法,以及BeanFactoryPostProcessor这一类的Bean加载过程中的一些前置和后置的一些处理扩展实现,这些类和配置其实是Springr提供给开发者用来去实现Bean加载过程中的一些扩展,在很多和Spring集成的中间件也比较常见,比如Dubbo,这样一些中间件。

创建实例化:这个阶段主要作用是通过反射去创建Bean的实例对象,并且会扫描和解析Bean声明的一些属性

依赖注入:如果被实例化的Bean存在依赖其他Bean对象的一些情况,则需要对这些依赖的Bean进行对象注入,比如常见的@Autowired,以及setter注入等这样一些配置形式,

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

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

相关文章

数学建模(1)

论文:做流程图 论文查重不能高于30% 论文 分模块备战 摘要不能超过一页的四分之三 数学建模的六个步骤: 【写作】---学术语言 团队练题

小阿轩yx-高性能内存对象缓存

小阿轩yx-高性能内存对象缓存 案例分析 案例概述 Memcached 是一款开源的高性能分布式内存对象缓存系统用于很多网站提高访问速度,尤其是需要频繁访问数据的大型网站是典型的 C/S 架构,需要构建 Memcached 服务器端与 Memcached API 客户端用 C 语言…

第四届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2025)

#先投稿,先送审# 第四届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2025) 2025 4th International Conference on Cyber Security, Artificial Intelligence and Digital Economy 重要信息 会议官网:www.csaide.net 会…

【 FPGA 线下免费体验馆】高端 AMD- xilinx 16 nm UltraScale +系列

在复杂的FPGA 开发的过程中,需要能够满足高速、高精度、多通道等的复杂应用。而一个简单的 FPGA 开发板是不具备这些的,因此需要用更高端,大容量,高速IO的 FPGA 芯片与其他硬件组成一个完整的系统开发。这里就产生了高端 FPGA 开发…

Docker搭建Harbor

1.什么是Harbor Harbor 是 vMware 公司开源的企业级 Docker 〖egistry 项日,其日标是帮助用户迅速搭建一个企业级的 Docker Registry 服务。Harbor以 Docker 公司开源的 Registry 为基础,提供了图形管理UI 、基于角色的访问控制(Role Based Accesscontr…

Web开发:ASP.NET CORE前后端交互之AJAX(含基础Demo)

目录 一、后端 二、前端 三、代码位置 四、实现效果 五、关键的点 1.后端传输给前端: 2.前端传输给后端 一、后端 using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.Rendering; using WebAppl…

MongoDB教程(十二):MongoDB数据库索引

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 文章目录 引言一、MongoD…

uni-app学习HBuilderX学习-微信开发者工具配置

HBuilderX官网:简介 - HBuilderX 文档 (dcloud.net.cn)https://hx.dcloud.net.cn/ uni-app官网: uni-app官网 (dcloud.net.cn)https://uniapp.dcloud.net.cn/quickstart-hx.htmlHBuilder下载安装:打开官网 uni-app项目的微信开发者工具配置…

人工智能正在影响无源和互连设计

人工智能 (AI) 应用通常涉及大型数据集。工作负载可能需要多个分布式 CPU 和 GPU 实时相互通信。这是高性能计算 (HPC) 架构的本质。 在处理元件之间路由高速数字信号引入了芯片到电路板和电路板到电路板的连接。通信协议和物理标准已经开发出来以满足高速要求,通常…

基于X86+FPGA+AI的远程医疗系统,支持12/13代 Intel Core处理器

工控主板:支持12/13代 Intel Core处理器,适用于远程医疗系统 顺应数字化、网络化、智能化发展趋势,国内医疗产业改革正在积极推进,远程医疗、智慧医疗等新模式新业态创新发展和应用,市场空间不断扩大,而基…

界面控件DevExpress Blazor UI v24.1 - 发布全新TreeList组件

DevExpress Blazor UI组件使用了C#为Blazor Server和Blazor WebAssembly创建高影响力的用户体验,这个UI自建库提供了一套全面的原生Blazor UI组件(包括Pivot Grid、调度程序、图表、数据编辑器和报表等)。 DevExpress Blazor控件目前已经升级…

园区AR导航系统构建详解:从三维地图构建到AR融合导航的实现

随着现代园区规模的不断扩大与功能的日益复杂,传统的二维地图导航已难以满足访客高效、精准定位的需求。园区内部错综复杂的布局、频繁变更的商户位置常常让访客感到迷茫,造成寻路上的时间浪费。园区AR导航系统以创新的技术手段,破解了私域地…

【Apache Doris】周FAQ集锦:第 16 期

【Apache Doris】周FAQ集锦:第 16 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目! 在这个栏目中,每周将筛选社区反馈的热门问题和话题,重点回答并进行深入探讨。旨在为广大用户…

Linux网络——套接字与UdpServer

目录 一、socket 编程接口 1.1 sockaddr 结构 1.2 socket 常见API 二、封装 InetAddr 三、网络字节序 四、封装通用 UdpServer 服务端 4.1 整体框架 4.2 类的初始化 4.2.1 socket 4.2.2 bind 4.2.3 创建流式套接字 4.2.4 填充结构体 4.3 服务器的运行 4.3.1 rec…

ROS2从入门到精通2-3:机器人3D物理仿真Gazebo与案例分析

目录 0 专栏介绍1 什么是Gazebo?2 Gazebo架构2.1 Gazebo前后端2.2 Gazebo文件格式2.3 Gazebo环境变量 3 Gazebo安装与基本界面4 搭建自己的地图4.1 编辑地图4.2 保存地图4.3 加载地图 5 常见问题 0 专栏介绍 本专栏旨在通过对ROS2的系统学习,掌握ROS2底…

车载通信与DDS标准解读系列(5):DDS-Security

DDS-Security协议与DDS协议、DDSI-RTPS协议、DDS-XTypes协议共同作为DDS协议簇中的核心协议。本协议基于其它三份核心协议,对系统中各交互环节的认证加密等措施进行规范化,保障用户发现和数据传递的安全性。协议于2016年发布v1.0,目前最新版本…

香橙派AIpro-携手华为-为AI赋能

文章目录 香橙派AIpro-携手华为-为AI赋能开箱和功能介绍开箱功能介绍 环境搭建镜像烧录进入系统 测试项目YOLOv5部署YOLOv5识别单张图片实时识别视频使用Ascend测试yolov5 产品评价 香橙派AIpro-携手华为-为AI赋能 今天新入手了一款香橙派AIPro,让我们一起跟着文章…

【Linux】线程——线程池、线程池的实现、线程安全的线程池、单例模式的概念、饿汉和懒汉模式、互斥锁、条件变量、信号量、自旋锁、读写锁

文章目录 Linux线程7. 线程池7.1 线程池介绍7.2 线程池的实现7.3 线程安全的线程池7.3.1 单例模式的概念7.3.2 饿汉和懒汉模式 8. 常见锁使用汇总8.1 互斥锁(Mutex)8.2 条件变量(Condition Variable)8.3 信号量(Semaph…

PostgreSQL的逻辑架构

一、PostgreSql的逻辑架构: 一个server可以有多个database;一个database有多个schema,默认的schema是public;schema下才是对象,其中对象包含:表、视图、触发器、索引等;与user之间的关系&#x…

【信号频率估计】MVDR算法及MATLAB仿真

目录 一、MVDR算法1.1 简介1.2 原理1.3 特点1.3.1 优点1.3.2 缺点 二、算法应用实例2.1 信号的频率估计2.2 MATLAB仿真代码 三、参考文献 一、MVDR算法 1.1 简介 最小方差无失真响应(Mininum Variance Distortionless Response,MVDR)算法最…