Spring 面试题之一

Spring 基础

Spring Bean 的五个作用域

类别 说明
singleton 在整个 Spring IOC 容器中,使用 singleton 定义的 Bean 将只有一个实例
prototype 每次通过容器的 getBean () 方法获取 prototype 定义的 Bean 时,都将产生一个新的 Bean 实例
request 对于每次 HTTP 请求,使用 request 定义的 Bean 都将产生一个新实例,即每次 HTTP 请求将会产生不同的 Bean 实例,只有在 Web 应用中(WebApplicationContext)使用 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 配置SpringVMC的字符编码过滤器 -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

解决 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-procss

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 执行