Spring高频面试题

2023最新版(持续更新)

  • 一、Spring高频面试题
    • 1. Spring框架中的单例bean是线程安全的吗?
    • 2. 什么是AOP,你们项目中有没有用到AOP?Spring中的事务是如何实现的?
    • 3.Spring中事务时效的场景有哪些?
    • 4. Spring中bean的生命周期
    • 5. Spring中bean的循环引用
    • 6. Spring中常见的注解

一、Spring高频面试题

1. Spring框架中的单例bean是线程安全的吗?

前置需要了解的知识:

  • 在Spring框架中我们可以通过@Scope(“singleton”)来将bean设置为单例;
  • singleton:bean在每个SpringIOC容器中只有一个实例。
  • prototype:一个bean的定义可以有多个实例。
    在这里插入图片描述

成员变量需要考虑线程安全问题,局部变量不需要考虑线程安全问题。
在这里插入图片描述

Spring bean并没有可变状态(例如Service类与Dao类),所以在某种程度上来说Spring的单例bean是线程安全的。

无可变状态的类(无状态的类):判断当前的成员变量能不能被修改,如果不能被修改,则称之为无状态的类,这种无状态的成员变量无线程安全问题。

总结:
Spring框架中的单例bean不是线程安全的!
Spring框架中有一个@Scope注解,默认值是singleton,是单例的。因为一般在spring的bean都是注入无状态的对象,并不会产生线程安全问题,如果在bean中定义了可修改的成员变量,需要考虑线程安全问题,可以使用多例或者加锁来解决。

对面试官的回答:
Spring框架中的单例bean不是线程安全的。
当出现多个用户同时请求一个服务的场景,容器会给每一个请求分配一个线程,多线程会并发的执行该请求对应的业务逻辑(成员方法),如果业务逻辑中有对该单例bean状态的修改(对该单例bean的成员属性进行修改),则必须考虑线程同步问题。

Spring框架并没有对单例bean进行任何的多线程封装处理,关于单例bean的线程安全问题和并发问题需要我们开发者自己去搞定。

比如:我们通常在项目中使用的Spring bean都是不可变状态的(例如Service类与Dao类),所以在某种程度上说Spring的单例bean是线程安全的。

但是如果你的bean是有多种状态(属性可以被修改)的话,就需要自己去保证线程的安全。比较简单的办法就是将单例bean变成多利bean,将@Scope(“”)注解中的值从singleton变更为prototype。

补充:线程安全与并发问题的异同?

并发问题是指多个线程同时访问共享资源时可能出现的问题,例如死锁、竞态条件等。并发问题通常需要使用同步机制来解决,例如锁、信号量等。
线程安全问题是指在多线程环境下,对共享资源的访问不会导致数据不一致或程序崩溃等问题。线程安全问题通常需要使用线程安全的数据结构或同步机制来解决,例如使用线程安全的集合类、使用 synchronized 关键字等。
因此,可以说并发问题是线程安全问题的一种表现形式,但并不是所有的线程安全问题都是并发问题。

2. 什么是AOP,你们项目中有没有用到AOP?Spring中的事务是如何实现的?

什么是AOP?
AOP称为面向切面编程,他主要的应用场景是将哪些与业务无关,但却对多个对象产生影响的公共行为和逻辑(例如事务,日志等),抽取并封装为一个可重用的模块,这个模块被命名为切面(Aspect),减少系统中的重复代码,降低模块间的耦合度,提高系统的可维护性。

spring事务的底层用到了AOP进行实现,而AOP的底层用到了动态代理去实现。

你们项目中有没有用到AOP?

常见的AOP使用场景:

  • 记录操作日志
  • 缓存的处理
  • Spring中内置的事务处理

记录操作日志实现核心:使用aop中的环绕通知+切点表达式(找到要记录日志的方法),通过环绕通知的参数获取请求方法的参数(类、方法、注解、请求方式等),获取到这些参数以后,保存到数据库中

Spring中的事务是如何实现的?
其本质是通过AOP功能,对方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后,根据执行情况提交或者回滚;

3.Spring中事务时效的场景有哪些?

场景一:异常捕获处理
在这里插入图片描述
原因:事务通知只有捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉了异常,则spring的事务无法洞悉,也就没有进行回滚。
解决方案:在catch块中手动将异常抛出,让spring的 事务能够察觉到即可完成在出现异常是进行事务回滚。

场景二:抛出检查异常
在这里插入图片描述
失效的原因:spring默认只会回滚非检查异常(Runtime异常),上方截图代码中抛出的是一个检查异常,因此事务失效;
解决方案:配置rollbackFor属性

@Transaction(rollbackFor = Exception.class)
该配置描述:只要是异常都会进行回滚;

场景三:非public方法导致事务失效
在这里插入图片描述
事务失效原因:Spring为方法创建代理,添加事务通知,前提条件是该方法是public的;
解决方案:将方法改为public的即可;

4. Spring中bean的生命周期

前置需要了解的知识
BeanDefinition:
Spring容器在实例化时,会将xml配置的的信息封装成BeanDefinition对象,Spring根据BeanDefinition来创建bean,该对象中有很多的属性来描述bean;
在这里插入图片描述

bean的生命周期图解:
在这里插入图片描述
回答面试官:

  1. 通过beanDefinition获取bean的定义信息
  2. 调用构造函数,实例化bean对象
  3. bean的依赖注入(通常情况下是通过set方法注入)
  4. 处理一系列的以Aware接口,实现其内部的方法,然后会执行它们
  5. bean的后置处理器BeanProcessor-前置
  6. 初始化方法:InitializingBean、init-method(自定义的一些初始化方法)
  7. bean的后置处理器BeanProcessor-后置
  8. 销毁bean

5. Spring中bean的循环引用

前置需要了解的知识
循环引用出现的场景:
在这里插入图片描述
产生循坏依赖的原因,与spring中bean的生命周期有关,直接上图理解:
在这里插入图片描述

为了帮助记忆,你可以理解为三个人在搞对象,三角恋,A喜欢B,心里只有B,而B心里只有C,C心里只有A,他们都是非心里那个它不娶,导致三人最后一起在养老院里玩耍
在这里插入图片描述

spring中有解决循环依赖的方案:三级缓存,如下图
在这里插入图片描述

缓存名称源码名称作用
一级缓存singletonObjects单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象
二级缓存earlySingletonObjects缓存早期的bean对象,此时的bean生命周期还没有走完
三级缓存singletonFactories缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的

三级缓存解决循环依赖:
一级缓存的作用:限制bean在beanFactory中只存一份,即实现singleton scope,它解决不了循环依赖;

打破循环依赖,需要一级缓存与二级缓存同时使用
二级缓存充当了一个中间人的存在(暂存区)

解决循环依赖的过程描述:

1.首先实例化A对象,此时会得到原始的实例对象A(当前的A对象是一个半成品对象)
2.将半成品对象A存入到二级缓存(earlySingletonObjects )中
3.此时A对象需要注入B对象,B对象此刻还不存在
4.实例化B,对象B的半成品也存入到二级缓存当中,此时二级缓存中有:对象A与对象B的半成品
5.此时对象B需要注入对象A,而对象A还没有初始化完成,单可以从二级缓存中拿出半成品对象A注入到对象B中,此时对象B就可以创建成功,将初始化后的对象存入单例池(一级缓存)中,并清除二级缓存中的半成品对象B;
6.正在初始化的对象A也能够从单例池获取B对象从而创建成功,并将创建成功的对象A存入到一级缓存中,并清除二级缓存中的半成品对象A;在这里插入图片描述
注意:一二级缓存只能解决非代理对象的循环依赖问题,对于代理对象的循环依赖问题需要三级缓存才能解决。

代理类出现循环依赖需要三级缓存才能解决:

1.实例化类A,会得到一个原始对象A,原始对象A生成一个ObjectFactory对象:A-ObjectFactory,并放入到三级缓存中;
2.此时对象A需要注入对象B,对象B还未存在;
3.实例化B获得原始对象B,用原始对象B生成一个ObjectFactory对象:B-ObjectFactory,并放入到三级缓存中;在这里插入图片描述
4.对象B此时需要注入对象A,但是对象A未初始化完,因此需要去三级缓存中获取A-ObjectFactory,通过A-ObjectFactory去生成对象A的代理(或普通的对象A),放入二级缓存中(此时生成的对象A的代理是一个半成品),对象B从二级缓存中拿出对象A的代理进行注入;
5.对象B完成初始化,存入到一级缓存中;
6.此时对象A可以注入对象B了,对象A(代理对象)也初始化成功,并放入一级缓存中
在这里插入图片描述

三级缓存解决产生循环依赖问题是在bean的初始化阶段的循环依赖问题 ,而无法结局bean生成时的循环依赖问题:
通过构造器注入依赖出现的问题,通过三级缓存解决不了,因此需要手动解决:
在这里插入图片描述

面试时的回答
spring中bean的循环引用

  • 循环依赖:循环依赖其实就是循环引用,也就是两个或者两个以上的bean相互持有对方,最终形成闭环,比如A依赖于B,B依赖于A;
  • 循环依赖在spring中是允许存在的,spring框架依据三级缓存已经解决了大部分的循环依赖
    • 一级缓存:单例池,缓存已经经历了完整的生命周期、已经初始化完成的bean;
    • 二级缓存:缓存早期的bean对象(生命周期未走完的bean);
    • 三级缓存:缓存的是ObjectFactory,表示工厂,用于创建某个对象;

(然后复述三级缓存解决循环依赖的流程,最好俩都说,记不起来就挑想得起来的说)

构造方法出现了循环依赖怎么解决?
原因:由于bean的生命周期中构造函数是第一个执行的,spring框架并不能解决构造函数的依赖注入
解决方案: 使用@Lazy进行懒加载,什么时候需要对象再进行bean的创建
在这里插入图片描述

6. Spring中常见的注解

注解说明
@Component、@Controller、@Service、@Repository使用在类上用于实例化bean
@Autowired使用在字段上用于根据类型依赖注入
Qualifier结合@Autowired一起使用,用于根据名称进行依赖注入
@Scop标注Bean的作用范围
@Configuration指定当前类是一个配置类,当创建容器时会从该类上加载注解
@ComponentScan用于指定在初始化容器时要扫描的包
@Bean使用在方法上,标注将该方法的返回值存储到Spring容器中
@Import使用@Import导入的类会被Spring加载到IOC容器中
@Aspect、@Before、@After、@Around、@Poincut用于切面编程(AOP)

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

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

相关文章

Redis数据结构 — Listpack

目录 listpack 结构 listpack 节点结构 quicklist 虽然通过控制 quicklistNode 结构里的压缩列表的大小或者元素个数,来减少连锁更新带来的性能影响,但是并没有完全解决连锁更新的问题。 于是,Redis 在 5.0 新设计一个数据结构叫 listpack…

03关于golang中各种运算符的讲解代码和注释

运算符 算术运算符:关系运算符:逻辑运算符:赋值运算符:位运算符: 在Golang中,运算符是用于执行各种数学和逻辑操作的符号。本文将对Golang中常见的运算符进行讲解,并提供一些示例代码和注释。 …

设计模式之单例

文章目录 前言一、单例模式的基本定义二、懒汉式单例三、饿汉式单例四、懒汉式单例存在的线程安全问题总结 前言 单例模式是比较经典的设计模式,本篇我们将结合实际案例说明单例模式的实现原理,以及存在的问题。 一、单例模式的基本定义 单例模式&…

STM32定义变量到指定内存位置

rt thread, 怎么定义变量到指定内存位置? OpenCat是由未来可编程机器人宠物制造商Petoi开发的基于Arduino和Raspberry Pi的开源四足机器人宠物框架。 非 gcc 版 定义一个宏 #ifndef __MEMORY_AT #if (defined (__CC_ARM)) #define _…

Vue--》打造个性化医疗服务的医院预约系统(一)

今天开始使用 vue3 ts 搭建一个医院预约系统的前台页面,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运…

Win11 设置FTP服务详细教程

起因: 因测试需要,本机建立FTP服务测试使用,此文章用于记录使用! 操作步骤: 1、配置FTP功能 ①、"winR" > 在运行窗口输入"control" 回车; ②、打开"控制面板" > 点击…

【专题速递】传输网络优化(长专题)

// RTC如何助力远程医疗?5G的差异化体现在哪?SMT如何将远程做到极致?7月29日LiveVideoStackCon2023上海站传输网络优化专场,为您解答。 传输网络优化 为应对互联网日益增长的加速需求、复杂的网络环境以及多种多样的视频业务&am…

Linux常见命令

这里写目录标题 Linux 背景知识Linux环境搭建方式使用终端软件连接到 LinuxLinux 常用命令特殊的目录:绝对路径 与 相对路径vim Linux 背景知识 Linux 是一个操作系统. 和 Windows 是 “并列” 的关系. 安卓系统本质上就是 Linux. 一个完整的操作系统 操作系统内核 配套的…

ylb-接口7注册发送短信

总览: 在common模块下引入短信验证码的依赖项(生成4位随机数): 在web模块下的resources/application.yml,添加配置信息(京东万象): #短信配置 jdwx:sms:url: https://way.jd.com…

ORB-SLAM2学习笔记2之TUM开源数据运行ORB-SLAM2生成轨迹并用evo工具评估轨迹

文章目录 0 引言1 evo工具1.1 简介1.2 常用命令1.3 安装 2 TUM数据3 单目ORB-SLAM23.1 运行ORB-SLAM23.2 evo评估轨迹3.2.1 载入和对比轨迹3.2.2 计算绝对位姿误差 4 RGB-D ORB-SLAM24.1 运行ORB-SLAM24.2 evo评估轨迹4.2.1 载入和对比轨迹4.2.2 计算绝对轨迹误差 ORB-SLAM2学习…

2003-Can‘t connect to Mysql server on ‘xxx‘ (10060 “Unknown error“)

Navicat连接 阿里云 服务器MySQL5.7数据库报错 解决办法: 进入数据库执行以下sql 1.允许root用户远程连接 GRANT ALL PRIVILEGES ON *.* TO root% IDENTIFIED BY 数据库密码 WITH GRANT OPTION; 2.刷新权限 FLUSH PRIVILEGES;3.执行quit退出数据库 quit; 4.…

uniapp连接到微信小程序

第一次使用uniapp连接到微信小程序,但是出现了define is not defined问题,让人头疼,出现这个问题的原因是 调试基础库 版本过高导致的! 解决办法: 点击设置,选择项目设置。,会进入到如下界面&a…