面试题由23年8月开始记录,主要参考B站黑马程序员的视频(新版Java面试专题视频教程,java八股文面试全套真题+深度详解(含大厂高频面试真题)_哔哩哔哩_bilibili)和JavaGuide(项目介绍 | JavaGuide),并在多次面试中二次改进并增加题目。内容仅供参考,建议理解使用。
前言
该篇主要分享Spring、SpringMVC、SpringBoot、Mybatis、SpringCloud的面试题,Spring、 Mybatis中的面试题在本人面试过程中被问较多,且皆是一环接一环。
Spring
Spring中的单例bean是线程安全的吗?
什么是AOP,你们项目中有没有使用到AOP
如果以往项目中没有使用过,建议自己动手实现简单的日志记录功能,理解记忆 此处贴出实例代码,仅供参考
@Aspect
@Component
public class ApiLogAspect {
private static final Logger log = LoggerFactory.getLogger(ApiLogAspect.class);
public PlatformApiLogAspect() {
}
@Pointcut("execution(public * org.springblade.*.controller..*.*(..))")
public void controllerPointCut() {}
@Pointcut("execution(public * org.springblade.*.endpoint..*.*(..))")
public void endPointPointCut() {}
@Around("controllerPointCut() || endPointPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
// 获取用户信息
BladeUser user = AuthUtil.getUser();
String account = null;
Long userId = null;
String userName = null;
if(ObjectUtil.isNotEmpty(user)){
account = user.getAccount();
userId = user.getUserId();
userName = user.getNickName();
}
// 反射获取类信息
String className = point.getTarget().getClass().getName();
String methodName = point.getSignature().getName();
Class cl1 = Class.forName(className);
Method[] declaredMethods = cl1.getMethods();
String title = null;
try {
title = Arrays.stream(declaredMethods)
.filter(x -> x.getName().equals(methodName))
.map(x -> x.getAnnotation(ApiOperation.class).value())
.collect(Collectors.toList()).get(0);
}catch (NullPointerException e){
log.error("{} -- {}: 无ApiOperation注解", className, methodName);
}
catch (Exception e){
log.error("{} -- {}: 反射异常", className, methodName);
}
long beginTime = System.currentTimeMillis();
Object result = point.proceed();
long time = System.currentTimeMillis() - beginTime;
// 异步记录操作
ApiLogPublisher.publishEvent(methodName, className, title, account
, userId, userName, time);
return result;
}
}
- 核心概念
- Joinpoin(连接点): 指那些被拦截到的点,在Spring中,指可以被动态代理拦截目标类的方法。
- Pointcut(切入点): 指要对哪些Joinpoin进行拦截,即
被拦截的连接点
。- Advice(通知): 指拦截到Joinpoint之后要做的事情,即
对切入点增强的内容
。- Target(目标): 指代理的目标对象。
- Weaving(植入): 指把增强代码应用到目标上,生成代理对象的过程。
- Proxy(代理): 指生成的代理对象。
- Aspect(切面): 切入点和通知的结合。
- 通知分类
- before(前置通知): 通知方法在目标方法
调用前
执行- after(后置通知): 通知方法在目标方法
返回或异常后
执行- after-returning(返回后通知): 通知方法会在
目标方法返回后
调用- after-throwing(抛出异常通知): 通知方法会在目标方法抛出异常后调用
- around(环绕通知): 通知方法会在目标方法
调用前和调用后
执行
Spring中事务失效的场景有哪些(建议根据以往项目中的实际情况来回答)
事务传播行为
传播类型 | 当前无事务 | 当前已存在事务 |
---|---|---|
MANDATORY | 抛出异常 | 使用当前事务 |
NEVER | 不创建事物,在无事务状态下执行方法 | 抛出异常 |
NOT_SUPPORTED | 不创建事物,在无事务状态下执行方法 | 暂停当前事务,在无事务状态下执行方法 |
SUPPORTS | 不创建事物,在无事务状态下执行方法 | 使用该事务 |
REQUIRED | 创建新的事务 | 使用该事务 |
REQUIRES_NEW | 创建新的事务 | 暂停当前事务,创建一个新的独立事务 |
NESTED | 创建新的事务 | 创建新的内嵌事物 |
Spring的bean的生命周期(没被问过,非大厂应该不会问那么细,毕竟工作中用不到 接手新项目时需要分析启动流程的时候有用到)
- IOC容器通过BeanDefinition
获取bean定义信息
- 执行BeanPostProcesseor实例化
前处理器
Bean实例化
- 执行BeanPostProcesseor实例化
后处理器
执行Bean依赖注入
(构造器冲突判断)- 执行Bean实现的
Aware接口方法
(BeanNameAware、BeanFactoryAware、BeanClassLoaderAware)- 执行BeanPostProcesseor
初始化前处理器
- 执行Bean的
@PostConstruct
注解方法- 执行Bean实现的
InitalzingBean接口方法
(AfterPropertiesSet)Bean初始化
- 执行BeanPostProcesseor
初始化后处理器
- 执行BeanPostProcesseor
销毁前处理器
- 执行Bean实现的
@PreDestroy
注解方法Bean注销
Spring中的循环引用
Spring 框架中用到了哪些设计模式?(了解即可,如果熟悉对应的设计模式与源码,可以展开聊聊)
-
工厂设计模式
- getBean
-
单例设计模式
- getSingleton
-
代理设计模式
- AOP
-
模板方法
- JdbcTemplate
-
观察者模式
- ApplicationEvent
- ApplicationListener
- applicationContext.publishEvent
-
适配器模式
- HandlerAdapter
-
装饰者模式
Application和Bootstrap的区别(被问到过,应该是考察是否了解SpringCloud中的配置文件要使用bootstrap,而不能使用application)
-
boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载
-
boostrap 里面的属性不能被覆盖
-
使用场景
- 使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
- 一些固定的不能被覆盖的属性
- 一些加密/解密的场景;
SpringMVC
MVC的核心组件
DispatcherServlet:
- 前端控制器,负责调度其他组件的执行,可降低不同组件之间的耦合性,是整个 Spring MVC 的核心模块。
Handler:
- 处理器,完成具体业务逻辑,相当于 Servlet 或 Action。
HandlerMapping:
- DispatcherServlet 是通过 HandlerMapping 将请求映射到不同的 Handler。
HandlerInterceptor:
- 处理器拦截器,是一个接口,如果我们需要做一些拦截处理,可以来实现这个接口。
HandlerExecutionChain:
- 处理器执行链,包括两部分内容,即 Handler 和 HandlerInterceptor(系统会有一个默认的 HandlerInterceptor,如果需要额外拦截处理,可以添加拦截器设置)。
HandlerAdapter:
- 处理器适配器,Handler 执行业务方法之前,需要进行一系列的操作包括表单数据的验证、数据类型的转换、将表单数据封装到 POJO 等,这一系列的操作,都是由 HandlerAdapter 来完成,DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler。
ModelAndView:
- 装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。
ViewResolver:
- 视图解析器,DispatcherServlet 通过它将逻辑视图解析成物理视图,最终将渲染结果响应给客户端。
SpringMVC的执行流程知道吗?
拦截器
拦截器是SpringMVC中的一个核心应用组件,主要用于处理多个 Controller的共性问题.当我们的请求由DispatcherServlet派发 到具体Controller之前首先要执行拦截器中一些相关方法,在这些 方法中可以对请求进行相应预处理(例如权限检测,参数验证),这些方法可以决定对这个请求进行拦截还是放行.
- 服务器一启动,就会创建拦截器对象
- 对拦截器配置延迟加载是没有用的
- 拦截器是单例的,整个过程,拦截器只有一个实例对象
拦截器需要
实现HandleInterceptor接口
,或者继承HandlerInterceptorAdaptor抽象类
;
- HandlerInterceptor接口的三个方法:
- preHandle() 是拦截器最先执行的方法,是在请求到达Controller之前执行的,其实就是拦截器用于拦截请求的,三个参数,分别是request,response,handelr就是这个请求要去找的后端处理器Controller.方法的返回值是bloolean类型,如果返回为false,就说明请求在此终结,不能执行后面的代码了.如果返回值为true,那么这个拦截器就要放行,将请求交给后端处理器Controller.
- 2,postHandle() 这个方法,是在后端控制器controller处理完请求之后,就执行的,这个方法,多了一个参数,ModelAndView,后端控制器controller处理请求可能需要返回页面和数据,所以会多一个ModelAndView,但是这个方法,是在渲染页面之前执行的,渲染热面是交个前端控制器来完成的.
- afterCompletion() 拦截器最后执行的方法
SpringBoot
优化手段(问到过,没答出来)
- 懒加载
- 延迟初始化数据库连接
- 减少自动配置的类
- 优化日志级别
- 使用JVM参数调优
- 精简依赖
- 优化Spring Beans
- 使用JVM的Just-In-Time (JIT) 编译优化
- 减少类路径扫描
- 使用Spring Boot DevTools的重启特性
Starter的作用
- 整合模块
- spring.factories文件
SpringBoot的自动配置原理(一般是指自动装配原理,两者意思不一样,面试中一般问的都是这个)
Spring框架常见的注解(Spring、Springboot、Springmvc)
面试中回答自己常用的即可,一定要知道注解的意思
- Spring
- @Component、@Controller、@Service、@Repository
- @Autowired
- @Qualifier
- @Scope
- @Configuration
- @ComponentScan
- @Bean
- @Import
- @Aspect、@Before、@After、@Around、@Pointcut
- SpringMVC
- @RequestMapping
- @RequestBody
- @RequestParam
- @PathVariable
- @ResponseBody
- @RequestHeader
- @RestController
- Srpingboot
- @SpringBootConfiguration
- @EnableAutuConfiguration
- @CompenentScan
跨域配置(被问过,其实就是问项目中有没有遇到跨域问题)
-
SpringBoot 配置 CORS 解决跨域
- implements WebMvcConfigurer
-
SpringBoot 通过 CorsFilter 解决跨域
- CorsFilter
-
SpringBoot 通过注解解决跨域
- @CrossOrigin
-
通过 nginx 配置 CORS 解决跨域
Mybatis
- 执行流程
- 延迟加载
- 一二级缓存
Mybatis执行流程
Mybatis是否支持延迟加载?
Mybatis的一级、二级缓存用过吗?
Mybatis的分页(被问到过,实际工作中也常用)
最近工作发现其实分页有很大技巧在里面,实际情况中的分页情况并没有那么理想,有个别情况是分页查出来的数据是10条,但又要经过一定的处理,处理后的数据又变成7条(仅是举例),这种情况最简单的方法就是全部查出来后手动分页。不过更多暂且不谈,日后有空详细写写。
-
数组分页
-
RowBounds内存分页
- RowBounds是将
所有
符合条件的数据全都查询到内存中,然后在内存中对数据进行分页,若数据量大,千万别使用RowBounds
- RowBounds是将
-
分页插件拦截器limit分页
-
sql手写limit分页
如何批量插入(被问到过)
- 循环单次插入
- foreach标签
- 批处理
SpringCloud
Spring Cloud 5大组件有哪些?
服务注册和发现是什么意思?Spring Cloud如何实现服务注册发现?
项目负载均衡如何实现的?
什么是服务雪崩,怎么解决这个问题?
微服务是怎么监控的?
项目中有没有做过限流?怎么做的?
解释一下CAP和BASE
采用哪种分布式事务解决方案?
分布式服务的接口幂等性如何设计?
项目中使用了什么分布式任务调度?
SpringCloud的跨域处理
- 在Controller上添加@CrossOrigin注解
- 增加WebMvcConfigurer全局配置
- 结合Filter使用
- 在Gateway端增加CorsFilter拦截器
- 在Gateway端增加CorsFilter拦截器
结语
这部分的面试题在本人以往面试中不太常见(可能是去的公司比较坑的缘故),而且基本上可以从这些面试题中了解到公司招聘的大概情况,如问的都是常见面试题,而且前后问题跨度较大(上一题问有没有使用过Spring事务,下一题不问事务失效情况而是问Spring生命周期),这种情况大概率是该公司只是喊来面试意思下而已,这时候就可以放平心态,大胆说出来自己对题目的想法,就当是来体验面试了。