Java后端面试:框架篇高频面试(Spring、SpringMVC、SpringBoot、MyBatis)

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:Java后端面试:MySQL面试篇(底层事务、SQL调优)
📚订阅专栏:Java后端面试
希望文章对你们有所帮助

框架篇高频面试(Spring、SpringMVC、SpringBoot、MyBatis)

  • Spring
    • 单例bean是线程安全的吗?
    • AOP相关面试题
    • Spring事务失效的场景
    • bean的生命周期
    • bean的循环依赖(循环引用)
  • SpringMVC-执行流程
    • 视图阶段(JSP)
    • 前后端分离阶段
  • SpringBoot-自动装配原理
  • Spring框架常见注解(Spring、SpringMVC、SpringBoot)
  • MyBatis
    • 执行流程
    • 延迟加载使用及原理
    • 一级、二级缓存

Spring

单例bean是线程安全的吗?

通过@Scope注解可以设置bean是单例的还是多例的,默认是单例的。
而单例bean线程不安全

Spring的bean中都是注入无状态的对象,也就是说无法修改,不会有线程安全问题。
但是如果在bean中定义了可修改的成员变量,是要考虑线程安全问题的,当然可以使用多例模式或者加锁来解决。

AOP相关面试题

AOP很重要,在Spring也算是一个难点吧,但是像IOC、AOP这种Spring核心,不会的话说不过去,这里就简单说说。

1、何为AOP?
AOP称为面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被称为切面(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

2、常见的AOP使用场景?

1、记录操作日志(自行学习@Aspect、切点、环绕通知)
2、缓存处理
3、Spring中内置的事务处理

3、Spring中的事务是如何实现的?(一定要提到AOP!)

Spring支持编程式事务管理和声明式事务管理两种方式,主要使用的是声明式事务
声明式事务管理是建立在AOP上的。本质是通过AOP功能,对方法的前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行目标方法之后执行情况提交或者回滚事务。(@Transactional注解就是这样的,其底层的实现(开启事务、提交/回滚事务)就是AOP追加的)

Spring事务失效的场景

这种问题能够体现出我们对Spring框架的深入理解,以及复杂业务的编码经验。

有三种非常常见的事务失效的情况:

1、异常捕获处理

对于转账的业务,我们会给整个业务增加@Transactional注解,如果中途发生了异常我们就会回滚。
但是如果这个业务方法中使用了try…catch,中途发生异常以后,@Transactional将会失效。
原因:事务通知只有捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知将会无法知悉
解决方法:在catch块中添加throw new RuntimeException(E),将异常给抛出,不要处理。

2、抛出检查异常

依旧是转账业务,这次不用try…catch,而是在方法体使用throws来抛出检查异常(类似FileNotFoundException这种非运行异常),这种情况也会导致事务失效。
原因:Spring默认只会回滚非检查异常
解决方法:配置rollbackFor属性:@Transactional(rollbackFor=Exception.class),这样事务回滚就不只是针对运行时异常了。

3、非public方法

如果没有用public修饰方法,就会导致事务失效。
原因:Spring为方法创建代理、添加事务通知,前提条件都是该方法是public的
解决:改为public方法

bean的生命周期

这个在业务开发过程中重要吗?可能真的不太重要,这就是个纯八股。但是面试官还是挺喜欢问的,可能是掌握生命周期能显得你更了解框架,方便调试和解决问题。

1、通过BeanDefinition获取bean的定义信息
2、调用构造函数实例化bean
3、bean的依赖注入
4、处理Aware接口
5、Bean的后置处理器BeanPostProcessor-前置
6、初始化方法
7、Bean的后置处理器BeanPostProcessor-后置
8、销毁bean

bean的循环依赖(循环引用)

如果是两个bean,成员变量分别用对方来注入,这就是循环依赖。
这种方式是会出现死循环的,对于A,先实例化bean,再初始化,初始化的过程中需要设置b属性,而b是B类型的对象,可是容器中不存在B对象,就会去实例化B的bean对象,再去初始化,初始化的时候需要设置a属性,a是A类型的对象,但是容器中也不存在A对象,最后造成了死循环。

Spring框架已经帮助我们解决了大部分的循环依赖问题,通过的是三级缓存:

一级缓存:单力池,缓存已经经历了完整声明周期,即已经初始化完成的bean对象
二级缓存:缓存早期的bean对象(生命周期还没走完)
三级缓存:缓存的是对象工厂ObjectFactory,用来创建某个对象的

整体流程非常的复杂,大家可以自行去看相关资料来理解,写起来很麻烦,但要记住一级缓存+二级缓存可以解决大部分的循环依赖问题,但是解决不了存在代理对象时的问题,而一级+二级+三级可以解决代理对象的循环依赖问题,过程需要理解。

这些都是发生在初始化的时候,而如果我们在声明周期的构造方法换发出现了循环依赖,也就是注入的方式是用构造函数。解决是使用@Lazy进行懒加载,什么时候需要对象了再进行bean对象的创建就好了。

SpringMVC-执行流程

如果要问到SpringMVC,那么执行流程可以说是非常重要的。
但是其实开发分为了两个阶段,一个是视图阶段(老旧的JSP等),另外一个是前后端分离阶段(接口开发,异步),现在我们都是用的前后端分离的开发,但是视图阶段的开发也是面试可能会问到的,很繁琐,得记住。

视图阶段(JSP)

在这里插入图片描述
1、对于一个浏览器发起的请求,视图阶段的执行流程如下:

1、浏览器发起请求给前端控制器DispatcherServlet
2、查询handler:前端控制器根据前端请求,去处理器映射器HandlerMapping中查询对应的执行方法
3、返回处理器执行链:因为对于一个请求,除了要找到这个路径对应的类名.方法名,还需要判断它是否会被拦截器拦截,因此处理器映射器不是直接返回方法给前端控制器,而是返回一个处理器执行链(处理器执行链可以暂且理解成方法handler+拦截器
4、请求执行handler:处理器执行链不会被拦截,那么前端控制器就要开始执行方法handler,这个执行需要向处理器适配器去请求,而不是直接到处理器中(适配器模式),用适配器有两个好处:
(1)可以处理请求的参数
(2)处理返回值
5、处理器适配器向处理器请求
6、处理器将响应返回给处理器适配器,这个响应就是ModelAndView
7、处理器适配器再将ModelAndView返回给前端控制器
8、前端控制器返回视图解析器ViewResolver,这个视图解析器的作用是将逻辑视图解析为真正的视图View
9、视图解析器将真正的视图View返回给前端控制器
10、前端控制器将视图渲染

2、SpringMVC执行过程中重要的四个组件

1、前端控制器DispatcherServlet(调度中心,处理所有的请求)
2、处理器映射器HandlerMapping(通过路径,查询方法handler,返回处理器执行链)
3、处理器适配器HandlerAdaptor(执行handler、处理handler中的参数)
4、视图解析器ViewResolver(将逻辑视图ModelAndView解析为真正的视图View)

前后端分离阶段

现在的开发不太一样,没有ModelAndView了,而是返回的Json数据,流程将会简化为:
在这里插入图片描述
这时候处理器Handler的执行是变化了:

1、处理器Handler的方法上添加@ResponseBody注解
2、底层会通过一个转化器HttpMessageConverter将返回结果转化为JSON格式响应给前端

SpringBoot-自动装配原理

这是SpringBoot最高频的面试题了,也是框架的最核心思想。

我们的SpringBoot启动类中一定会有一个注解:@SpringBootApplication,这个注解底层包含了三个部分:

@SpringBootConfiguration:与@Configuration相同,用来声明当前是个配置类
@ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包
@EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解

其中,@EnableAutoConfiguration是实现自动化配置的核心注解,该注解底层通过@Import来导入对应的配置选择器。

其内部就是读取该项目和该项目引用的jar包的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。
这个条件判断会有@ConditionalOnClass这样的注解,判断是否有对应的class文件(字节码文件),若有则加载该类,把这个配置类中所有的Bean都放入Spring容器中使用。

Spring框架常见注解(Spring、SpringMVC、SpringBoot)

Spring的注解主要是用来进行bean的实例化以及依赖注入的,SpringMVC的注解主要是用来处理请求和响应的,而SpringBoot的注解尽量说一下跟自动装配有关系的,被问到不要混淆着讲。
1、Spring注解:

注解说明
@Componennt、@Controller、@Service、@Repository使用在类上,用于实例化bean
@Autowired在字段上根据类型依赖注入
@Qualifier结合@Autowired一起使用,用于根据名称进行依赖注入
@Scope标注Bean的作用返回(单例or多例)
@Configuration指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解
@ComponentScan用于指定Spring在初始化容器时要扫描的包
@Bean用在方法上,标注该方法的返回值会存到Spring容器中
@Import该注解导入的类会被Spring加载到IOC容器中
@Aspect、@Before、@After、@Around、@Pointcut用于AOP(切面、前置通知、后置通知、环绕通知、切入点表达式)

2、SpringMVC注解:

注解说明
@RequestMapping(也有衍生的PostMapping、GetMapping等)用于映射请求路径,定义在类上或方法上,用在类上则该类中的所有方法都是以该地址作为父路径的
@RequestBody接受http请求的json数据,将json转化为java对象
@ResponseBody将controller方法返回的对象转化为json对象响应给客户端
@RequestParam指定请求参数的名称(和数据库字段名不一致时使用)
@PathViriable从请求路径下获取请求参数/user/{id},传递给方法的形式参数(Restful风格)
@RequestHeader获取指定的请求头数据
@RestController@Controller+@ResponseBody

3、SpringBoot注解:

注解说明
@SpringBootConfiguration配置文件
@EnableAutoConfiguration打开自动配置
@ComponentScanSpring组件扫描

MyBatis

执行流程

1、读取MyBatis配置文件mybatis-config.xml,加载运行环境(数据库相关信息)和mapper映射文件
2、构造会话工厂SqlSessionFactory,会话工厂是全局唯一的
3、会话工厂创建SqlSession对象(包含了执行SQL语句的所有方法),每次操作都会创建出一个会话
4、Executor执行器是真正操作数据库的接口,同时负责了查询缓存的维护
5、Executor接口的执行方法中有一个MappedStatement类型的参数,封装了映射信息
6、输入参数的映射(将java类型转化为数据库处理的类型)
7、输出结果映射(将数据库操作的结果映射成java类型)

延迟加载使用及原理

1、延迟加载是需要用到数据的时候才会加载,不需要的时候就不会加载。
2、MyBatis是支持延迟加载的,但是默认是没有开启的。可以局部开启或者全局开启。
3、延迟加载的底层原理:

(1)使用CGLIB创建目标对象的代理对象
(2)当调用方法的时候,进入拦截器invoke方法,发现目标方法是null值,执行SQL查询
(3)获取数据后,调用set方法设置属性值,再继续查询目标方法,就有值了

一级、二级缓存

一级缓存:基于HashMap本地缓存,其存储作用域为SqlSession,当SqlSession进行flush或close之后,该Session中的Cache就被清空(默认开启)
二级缓存:基于namespace和mapper的作用域起作用的,不依赖于SqlSession,默认也是基于HashMap存储,需要单独开启(通过核心配置文件)

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

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

相关文章

数字化转型导师坚鹏:人工智能在金融机构数字化转型中的应用

人工智能在金融机构数字化转型中的应用 课程背景: 金融机构数字化转型离不开人工智能,在金融机构数字化转型中,人工智能起到至关重要的作用,很多机构存在以下问题: 不清楚人工智能产业对我们有什么影响?…

C++_day4:成员函数版本和全局函数版本实现算术运算符的重载

1、成员函数版本和全局函数版本实现算术运算符的重载 程序代码&#xff1a; #include <iostream>using namespace std;//封装一个 名叫Number 的类 class Number {//全局函数做友元&#xff0c;让一些函数访问一个类的私有数据成员friend const Number operator-(const…

JavaWeb后端——分层解耦 IOC DI

分层/三层架构概述 三层架构&#xff1a;Controller、Service、Dao 解耦/IOC&DI概述 分层解耦 容器称为&#xff1a;IOC容器/Spring容器 IOC 容器中创建&#xff0c;管理的对象&#xff0c;称为&#xff1a;bean 对象 IOC&DI入门 实现 IOC&DI 需要的注解&#…

产品经理:前端实现网页防篡改,你会怎么做?

公众号&#xff1a;程序员白特&#xff0c;欢迎一起交流学习~ 如果产品经理要求系统中某个页面的输入框做防止篡改处理&#xff0c;你会怎么做呢&#xff1f; 需求梳理 首先&#xff0c;什么是防篡改&#xff1f; 简单来说&#xff0c;就是用户输入input框值&#xff0c;我们…

TrueNAS怎么设置中文,最新2024版本安装详细说明

首先我们做好安装前的准备工作 1&#xff0c;ISO镜像安装包 2&#xff0c;虚拟机&#xff08;建议使用ESXI虚拟机环境&#xff09; 如果是物理机安装&#xff0c;建议先给底层安装虚拟机系统esxi&#xff0c;再在上面安装方便以后的管理&#xff0c;如果你想物理机直接安装&a…

【SpringCloud】使用Seata实现分布式事务

目录 一、Seata 框架的需求背景二、Seata 事务模式与架构2.1 Seata 组成2.2 Seata 事务模式 三、Seata 实战演示3.1 部署 Seata Server3.1.1 下载 Seata Server3.1.2 更改 Seata Server 配置3.1.3 创建 Seata Server 所需的数据库、数据库表3.1.4 启动 Seata Server 3.2 Seata …

二叉搜索树题目:将有序链表转换为二叉搜索树

文章目录 题目标题和出处难度题目描述要求示例数据范围 前言解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;将有序链表转换为二叉搜索树 出处&#xff1a;109. 将有序链表转换为二叉搜索树 难度 5 级 题目描述 要求 …

士兵排列问题

解法一&#xff1a; deque实现队头入队和队尾入队即可得到编号排列&#xff0c;每个士兵有二个属性&#xff1a;编号、能力值。 #include<iostream> #include<algorithm> #include<deque> #include<vector> using namespace std; #define endl \n st…

苍穹外卖-day04:项目实战-套餐管理(新增套餐,分页查询套餐,删除套餐,修改套餐,起售停售套餐)业务类似于菜品模块

苍穹外卖-day04 课程内容 新增套餐套餐分页查询删除套餐修改套餐起售停售套餐 要求&#xff1a; 根据产品原型进行需求分析&#xff0c;分析出业务规则设计接口梳理表之间的关系&#xff08;分类表、菜品表、套餐表、口味表、套餐菜品关系表&#xff09;根据接口设计进行代…

搜索二叉树迭代和递归的两种*简单*实现方式

判断搜索二叉树 概念 一棵树所有结点的左节点小于父节点&#xff0c;右节点大于父节点&#xff0c;则为搜索二叉树。 迭代方法 中序遍历二叉树&#xff0c;如果总是升序则是搜索二叉树。如果存在降序&#xff0c;那肯定不是搜索二叉树。 Coding checkTreeOrder()方法 boo…

python 基础知识点(蓝桥杯python科目个人复习计划65)

今日复习内容&#xff1a;做题 例题1&#xff1a;遥远的雪国列车 问题描述&#xff1a; 小蓝和小红今天在房间里一起看完了“雪国列车”这部电影&#xff0c;看完之后他们感触颇深&#xff0c;同时他们想到了这样一道题目&#xff1a; 现在有一个数轴&#xff0c;长度为N&a…

代码随想录算法训练营第二十五天|216.组合总和III,17.电话号码的字母组合

216.组合总和III 题目 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数&#xff0c;并且每种组合中不存在重复的数字。 说明&#xff1a; 所有数字都是正整数。 解集不能包含重复的组合。 示例 1: 输入: k 3, n 7 输出: [[1,2,4]] 示例 2: 输入…