Spring 面试题之一
Spring 基础
Spring Bean 的五个作用域
类别 | 说明 |
---|---|
singleton | Spring IOC 容器一开始就会实例化该 Bean,且在整个 Spring IOC 容器中,使用 singleton 定义的 Bean 将只有一个实例 |
prototype | Spring IOC 容器一开始不会实例化该 Bean,而是每次通过容器的 getBean () 方法获取 prototype 定义的 Bean 时,都将产生一个新的 Bean 实例 |
request | 对于每次 HTTP 请求,使用 request 定义的 Bean 都将产生一个新实例,即每次 HTTP 请求将会产生不同的 Bean 实例,只有在 Web 应用中使用 Spring 时,该作用域才有效 |
session | 对于每次 HTTP Session,使用 session 定义的 Bean 都将产生一个新实例,同样只有在 Web 应用中使用 Spring 时,该作用域才有效 |
globalsession | 每个全局的 HTTP Session,使用 session 定义的 Bean 都将产生一个新实例,同样只有在 Web 应用中使用 Spring 时,该作用域才有效 |
其中比较常用的是 singleton 和 prototype 两种作用域。对于 singleton 作用域的 Bean,每次请求该 Bean 都将获得相同的实例,容器负责跟踪 Bean 实例的状态,负责维护 Bean 实例的生命周期;如果一个 Bean 被设置成 prototype 作用域,程序每次请求该 id 的 Bean 时,Spring 都会新建一个 Bean 实例,然后返回给程序。在这种情况下,Spring 容器仅仅使用 new 关键字创建 Bean 实例,一旦创建成功,容器不在跟踪实例,也不会维护 Bean 实例的状态。如果不指定 Bean 的作用域,Spring 默认使用 singleton 作用域。Java 在创建实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype 作用域下 Bean 的创建、销毁代价比较大;而 singleton 作用域的 Bean 实例一旦创建成功,可以重复使用。因此,除非必要,应尽量避免将 Bean 被设置成 prototype 作用域。
Spring MVC
Spring MVC 中解决请求乱码
解决 POST 请求乱码
1 | <!-- 配置SpringVMC的字符编码过滤器 --> |
解决 GET 请求乱码
方法一,通过 Java 代码手动指定字符编码:
1 | String name = new String (resuest.getParameter("name").getBytes("ISO8859-1"), utf-8); |
方法二,通过配置 Tomcat 的 server.xml
配置文件指定字符编码:
1 | <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/> |
Spring MVC 的工作流程
Spring MVC 处理模型数据
- 处理模型数据的方式一:将 Controller 中方法的返回值设置为 ModelAndView
- 处理模型数据的方式二:将 Controller 中方法的返回值设置为 String,在方法的入参中传入 Map、Model 或者 ModelMap
- 上述的两种方式,最终都会被 Spring MVC 转换为一个 ModelAndView 对象
Spring MVC 工作原理图
Spring MVC 工作流程
Spring MVC 各组件
- DispatcherServlet:中央控制器,也称为前端控制器,它是整个请求响应的控制中心,组件的调用由它统一调度
- HandlerMapping:处理器映射器,它根据用户访问的 URL 映射到对应的后端处理器 Handler。也就是说它知道处理用户请求的后端处理器,但是它并不执行后端处理器,而是将后端处理器告诉给中央处理器
- HandlerAdapter:处理器适配器,它调用后端处理器中的方法,返回逻辑视图 ModelAndView 对象
- ViewResolver:视图解析器,将 ModelAndView 逻辑视图解析为具体的视图(如 JSP)
- Handler:后端处理器,对用户具体请求进行处理,也就是 Controller 类
Spring MVC 的工作流程:
- 1)用户向服务端发送一次请求,这个请求会先到中央控制器 DispatcherServlet(前端控制器)
- 2)DispatcherServlet 接收到请求后会调用 HandlerMapping 处理器映射器。由此得知,该请求该由哪个 Controller 来处理(此时并未调用 Controller,只是得知)
- 3)DispatcherServlet 调用 HandlerAdapter 处理器适配器,告诉处理器适配器应该要去执行哪个 Controller
- 4)HandlerAdapter 处理器适配器去执行 Controller 并得到 ModelAndView (数据和视图),并层层返回给 DispatcherServlet
- 5)DispatcherServlet 将 ModelAndView 交给 ViewReslover 视图解析器解析,然后返回真正的视图
- 6)DispatcherServlet 将模型数据填充到视图中
- 7)DispatcherServlet 将结果响应给用户
Spring 数据库事务
Spring 的七种事务传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能在现有的事务中运行,也可能开启一个新的事务,并在自己的事务中运行。Spring 定义了七种事务传播行为,默认的事务传播行为是 PROPAGATION_REQUIRED
。
传播行为 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果存在一个事务,则支持当前事务;如果没有事务则开启 |
PROPAGATION_SUPPORTS | 如果存在一个事务,支持当前事务;如果没有事务,则非事务的执行 |
PROPAGATION_MANDATORY | 如果已经存在一个事务,支持当前事务;如果没有一个活动的事务,则抛出异常 |
PROPAGATION_REQUIRES_NEW | 总是开启一个新的事务;如果一个事务已经存在,则将这个存在的事务挂起 |
PROPAGATION_NOT_SUPPORTED | 总是非事务地执行,并挂起任何存在的事务 |
PROPAGATION_NEVER | 总是非事务地执行,如果存在一个活动事务,则抛出异常 |
PROPAGATION_NESTED | 如果有一个活动的事务存在,则运行在一个嵌套的事务中;如果没有活动事务,则按 PROPAGATION_REQUIRED 执行 |