spring面试题
牛客论坛01-Spring常见面试题
Spring中的IoC和AOP是什么?它们的作用是什么?
IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过, IoC 并非 Spring 特有,在其他语言中也有应用。所以说,控制反转是一种思想,目的是为了降低了代码耦合度,提升了系统的灵活性和可维护性。
在没有IoC容器的情况下,比如类A通过
new关键字直接实例化类B,对象创建和依赖关系由开发者手动控制,代码耦合度高,难以维护和扩展。而在有IoC容器的情况下,IoC容器负责实例化类A和类B,并管理它们的依赖关系,主函数只需从容器中获取所需对象,无需手动创建。所谓控制,就是指的是对象的创建(实例化,管理什么的),反转指的是将控制权交给外部框架(spring框架,IoC容器)。IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。在实际项目中一个 Service 类可能依赖了很多其他的类,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
其实在spring中IoC就是一个实现IoC的载体,是一个Map,其中存放着各种对象,早期是通过XML来配置的Bean,后面SpringBoot注解配置更好,只需加上
@Autowired或@Resource,Spring 就会自动注入依赖对象慢慢流行起来。
AOP是面向切面编程,能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK 动态代理,去创建代理对象,而对于没有实现接口的对象,就无法进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理。
Spring MVC
其流程大概是以下几个步骤:

流程说明(重要):
- 客户端(浏览器)发送请求,
DispatcherServlet拦截请求。(dis po cher servlet) DispatcherServlet根据请求信息调用HandlerMapping。HandlerMapping根据 URL 去匹配查找能处理的Handler(也就是我们平常说的Controller控制器) ,并会将请求涉及到的拦截器和Handler一起封装。DispatcherServlet调用HandlerAdapter适配器执行Handler。Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。Model是返回的数据对象,View是个逻辑上的View。ViewResolver会根据逻辑View查找实际的View。DispaterServlet把返回的Model传给View(视图渲染)。- 把
View返回给请求者(浏览器)
上述流程是传统开发模式(JSP,Thymeleaf 【time leaf】等)的工作原理。然而现在主流的开发方式是前后端分离,这种情况下 Spring MVC 的 View 概念发生了一些变化。由于 View 通常由前端框架(Vue, React 等)来处理,后端不再负责渲染页面,而是只负责提供数据,因此:
- 前后端分离时,后端通常不再返回具体的视图,而是返回纯数据(通常是 JSON 格式),由前端负责渲染和展示。
View的部分在前后端分离的场景下往往不需要设置,Spring MVC 的控制器方法只需要返回数据,不再返回ModelAndView,而是直接返回数据,Spring 会自动将其转换为 JSON 格式。相应的,ViewResolver也将不再被使用。
怎么做到呢?
- 使用
@RestController注解代替传统的@Controller注解,这样所有方法默认会返回 JSON 格式的数据,而不是试图解析视图。 - 如果你使用的是
@Controller,可以结合@ResponseBody注解来返回 JSON。
“在传统 Spring MVC 中,
DispatcherServlet拦截请求后,通过HandlerMapping查找Controller,执行处理并返回ModelAndView,最后由ViewResolver解析视图并渲染返回。而在前后端分离模式下,后端通过@RestController或@ResponseBody直接返回 JSON 数据,由前端负责渲染,ViewResolver和视图渲染流程不再需要。这种模式更符合现代开发需求,提升了开发效率和系统灵活性。”
Spring, Spring MVC, SpringBoot直接有什么关系?
Spring 是一个开源的 Java 企业级开发框架,主要提供 IoC(控制反转)和 AOP(面向切面编程)功能,简化 Java 开发。Spring MVC 是 Spring 框架中的一个子模块,专门用于构建 Web 应用,它基于 MVC(Model-View-Controller)设计模式,提供了强大的请求处理、数据绑定、视图解析等功能,适用于开发传统的 Java Web 应用。而 Spring Boot 是在 Spring 基础上发展而来的,它简化了 Spring 的配置,提供了一套开箱即用的默认配置,并且内置了 Tomcat 等 Web 服务器,让开发者可以快速构建独立运行的 Spring 应用,而无需手动配置 XML 或复杂的 Bean 管理。简单来说,Spring 是一个大框架,Spring MVC 负责 Web 层,而 Spring Boot 进一步简化了 Spring 的使用,提升了开发效率。
Spring框架中用了哪些设计模式?
工厂设计模式 : Spring 使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
什么是spring的bean?
Bean 代指的就是那些被 IoC 容器所管理的对象。
我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类。
Bean的注解有哪些?
@Component:通用的注解,可标注任意类为Spring组件。如果一个 Bean 不知道属于哪个层,可以使用@Component注解标注。
@Repository: 对应持久层即 Dao 层,主要用于数据库相关操作。
@Service: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
@Controller: 对应 Spring MVC 控制层,主要用于接受用户请求并调用Service层返回数据给前端页面。
spring的事务
事务是逻辑上的一组操作,要么都执行,要么都不执行。
Spring 事务传播机制有哪些
propagation 代表事务的传播行为,默认值为 Propagation.REQUIRED,其他的属性信息如下

@Transactional的其他属性有哪些?
timeout 属性
timeout :事务的超时时间,默认值为 -1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
readOnly 属性
readOnly :指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
isolation 属性
isolation :事务的隔离级别,默认值为Isolation.DEFAULT
Isolation.DEFAULT:使用底层数据库默认的隔离级别。
Isolation.READ_UNCOMMITTED:读未提交
Isolation.READ_COMMITTED:读已提交
Isolation.REPEATABLE_READ:可重复读
Isolation.SERIALIZABLE:串行化rollbackFor 属性
rollbackFor :用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。
noRollbackFor属性
noRollbackFor:抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。
MyBatis中的#{}和${}的区别是什么?如何防止SQL注入?
在 MyBatis 中,
#{}和${}是两种不同的参数占位符,它们的主要区别在于处理方式和安全性。#{}是预编译占位符,MyBatis 会将其替换为?,并通过PreparedStatement设置参数值,这种方式会对参数值进行转义,从而有效防止 SQL 注入,适合用于传递参数值,例如WHERE id = #{id}。而${}是字符串替换,MyBatis 会直接将值拼接到 SQL 语句中,这种方式不会对参数值进行转义,因此存在 SQL 注入风险,通常用于动态拼接表名、列名等场景,例如ORDER BY ${columnName}。为了防止 SQL 注入,推荐优先使用
#{},因为它能够自动处理参数值的转义,确保安全性。如果必须使用${},应确保拼接的值是可信的,例如动态表名或列名,而不是用户输入的直接拼接。此外,还可以通过以下方式进一步增强安全性:严格校验用户输入,确保其符合预期格式;使用 MyBatis 的动态 SQL 标签(如<if>、<choose>)生成安全的 SQL 语句,避免手动拼接 SQL;遵循最小权限原则,限制数据库用户的权限,避免使用高权限账号执行 SQL 操作。通过这些方法,可以有效防止 SQL 注入,确保应用的安全性。
@Transactional失效场景与解决办法
1、@Transactional 应用在非 public 修饰的方法上
2、@Transactional 注解属性 propagation 设置错误
3、@Transactional 注解属性 rollbackFor 设置错误
4、同一个类中方法调用,导致@Transactional失效
6、数据库引擎不支持事务
同一Service内方法A(无@Transactional)调用方法B(有@Transactional)是否生效?
好的,面试官!我来具体回答这个问题。
在同一 Service 内,如果方法 A(没有 @Transactional)调用方法 B(有 @Transactional),那么方法 B 的事务不会生效。原因是 Spring 的事务管理是基于代理机制实现的,当方法 A 直接调用方法 B 时,实际上是目标对象内部的方法调用,而不是通过代理对象调用,因此事务拦截器不会起作用。
为什么不会生效?
• Spring 的事务是通过 AOP 动态代理实现的,代理对象会在方法调用前后添加事务管理的逻辑。
• 当方法 A 调用方法 B 时,是直接调用目标对象的方法,而不是通过代理对象调用,所以事务拦截器不会生效。
如何解决?
- 将方法 A 和方法 B 拆分到不同的类中:通过代理对象调用方法 B,确保事务生效。
- 使用
AopContext.currentProxy()获取当前代理对象:在方法 A 中通过代理对象调用方法 B。1
((YourService) AopContext.currentProxy()).methodB();
- 在方法 A 上添加
@Transactional注解:让整个调用链处于事务管理之下。
总结:
同一 Service 内方法 A 调用方法 B 时,方法 B 的事务不会生效,因为直接调用绕过了代理机制。需要通过拆分类、使用代理对象或在方法 A 上加事务注解来解决。
以上就是我的回答,谢谢!
HTTP
超文本传输协议,用于传输HTML等内容的应用层协议,规定了浏览器和服务器之间如何通信的,以及通信时的数据格式。
好的,面试官!我来回答这个问题。
1. HTTP 报文结构及内容类型标识?
HTTP 报文分为请求报文和响应报文,结构如下:
请求报文
- 请求行:包含请求方法(如
GET、POST)、请求 URL 和 HTTP 版本。1
GET /index.html HTTP/1.1
- 请求头:包含客户端信息、请求内容类型等。
1
2Host: www.example.com
Content-Type: application/json - 请求体:可选,用于传递数据(如
POST请求中的表单或 JSON 数据)。
响应报文
- 状态行:包含 HTTP 版本、状态码和状态描述。
1
HTTP/1.1 200 OK
- 响应头:包含服务器信息、响应内容类型等。
1
2Content-Type: text/html
Content-Length: 1234 - 响应体:可选,包含返回的数据(如 HTML 页面或 JSON 数据)。
内容类型标识
• 通过 Content-Type 头字段标识报文体的格式,例如:
• text/html:HTML 文档
• application/json:JSON 数据
• application/x-www-form-urlencoded:表单数据
• multipart/form-data:文件上传
2. 如何判断请求体格式?
判断请求体格式主要通过 Content-Type 头字段:
- 检查
Content-Type头字段:例如:
•application/json:请求体是 JSON 格式。
•application/x-www-form-urlencoded:请求体是键值对形式的表单数据。
•multipart/form-data:请求体包含文件上传。 - 解析请求体:根据
Content-Type的值,使用相应的解析方式:
• JSON 格式:使用 JSON 解析库(如Jackson、Gson)解析。
• 表单数据:通过框架(如 Spring MVC)自动解析为Map或对象。
• 文件上传:通过MultipartFile处理。
示例:
• 如果 Content-Type 是 application/json,请求体可能是:
1
{"name": "John", "age": 30}
• 如果 Content-Type 是 application/x-www-form-urlencoded,请求体可能是:
1
name=John&age=30


