Spring MVC请求处理流程

1
2
3
环境: 
- org.springframework:spring-webmvc:5.3.10
- org.springframework.boot:spring-boot:2.5.5

web程序启动时的初始化顺序: ServletContext -> listener -> filter -> servlet spring bean的初始化是在listener中声明的, 可以在后面使用.

Filter

  • Servlet规范规定的,只能用于Web程序中, 由Servlet容器提供支持
  • 作用于Servlet执行前后
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Order(1)
@WebFilter(filterName = "customized", urlPatterns = "/*")
public class CustomizedFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("CustomizedFilter Init");
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("CustomizedFilter doFilter before");

// 执行Servlet
filterChain.doFilter(servletRequest, servletResponse);

log.info("CustomizedFilter doFilter after");
}

@Override
public void destroy() {
log.info("CustomizedFilter destroy");
}
}

必须要注解ServletComponentScan才能让自定义的Filter其效果.

在filterChain.doFilter调用的前后来执行操作, 作用于Servlet之前的前后.

DispatcherServlet

为Spring框架定制的Servlet, 用来对请求进行处理

  • 获取请求处理链HandlerExecutionChain以及相应的HandlerAdapter
  • 通过HandlerAdapter对请求进行处理
  • 使用Interceptor对request/response进行拦截
  • 对异常进行处理

Spring MVC中的各种相关配置可参考WebMvcAutoConfigurationAdapter. 通过定义一个或者多个WebMvcConfigurer来扩展Spring MVC中的配置

获取Handler

通过@RequestMapping注解定义方法Handler的匹配要求, 生成对应的RequestMappingInfo和多个RequestCondition, 用于请求匹配, 匹配成功后调用对应的方法Handler。

1
2
3
4
5
6
7
8
9
@RequestMapping(value = "/{ping}", method = RequestMethod.GET)
public String getPingPong( String ping) {
return ping;
}

@GetMapping(value = "/{ping}", params = "ex=1")
public String getPingPongEx( String ping) {
return ping + " Ex";
}

DispatcherServlet::getHandler用于获取请求处理链HandlerExecutionChain, 通过比较RequestMappingInfo和RequestCondition,查找最匹配的方法Handler。 定义的RequestCondition越多,则方法Handler的针对性越强;反之,则方法Handler越通用。

通过HandlerAdapter处理请求

HandlerAdapter.handle主要做以下几件事:

  • HandlerMethodArgumentResolver对输入参数进行解析
  • 调用handler对请求进行处理
  • HandlerMethodReturnValueHandler对返回进行处理
  • ExceptionHandler异常统一处理

基于String输入的参数解析

通过定义Converters中的bean,就可以在启动时 通过WebMvcAutoConfigurationAdapter#addFormatters添加进来, 用于AbstractNamedValueMethodArgumentResolver的输入类型转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Money.java
@Getter
@Setter
public class Money {
private String currency = "CNY";
private String value;

@Override
public String toString() {
return currency + " " + value;
}
}

// MoneyFormatter.java
@Component
public class MoneyFormatter implements Formatter<Money> {
@Override
public Money parse(String text, Locale locale) throws ParseException {
String[] input = text.split(" ");
Money money = new Money();
if (input.length == 1) {
money.setValue(input[0]);
} else {
money.setCurrency(input[0]);
money.setValue(input[1]);
}
return money;
}

@Override
public String print(Money object, Locale locale) {
return object.getCurrency()
+ " " + object.getValue();
}
}

// IndexController.java
@GetMapping(value = "/price")
public Money price( Money money) {
return money;
}

针对Body的输入和输出处理

通过HttpMessageConverter对body进行序列化和反序列化, 其中最常用的就是json的处理模块MappingJackson2HttpMessageConverter.

通过定义HttpMessageConverters的bean,将自定义的HttpMessageConverter添加进来, 通过WebMvcAutoConfigurationAdapter#configureMessageConverters进行注册

1
2
3
4
5
6
7
8
9
10
// StringConverter.java
public StringConverter implements HttpMessageConverter<String> {
...
}

// ConverterConfig.java
@Bean
public HttpMessageConverters converters() {
return new HttpMessageConverters(new StringConverter());
}

JacksonJson序列化的支持

Spring MVC中提供了MappingJackson2HttpMessageConverter对json对象进行序列化处理。 通过JsonComponnet相关的bean来注册JSON序列化组件

  • JsonSerializer
  • JsonDeserializer
1
2
3
4
5
6
7
8
9
10
11
12
@JsonComponent
public class MoneyJson extends StdSerializer<Money> {

protected MoneyJson() {
super(Money.class);
}

@Override
public void serialize(Money money, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(money.toString());
}
}

Interceptor

Interceptor用于对Controller层进行拦截, 处理一些和controller没有依赖的业务,比如鉴权,日志等

  • 作用于Controller前后执行
  • 不能修改request
  • spring中优先使用Interceptor, 而不是filter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class CustomizedInterceptor extends HandlerInterceptorAdapter {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info("CustomizedInterceptor prehandle");
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
log.info("CustomizedInterceptor postHandle");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
log.info("CustomizedInterceptor afterCompletion");
}

}

// 添加interceptor
@Configuration
public class AppServiceConfig extends WebMvcConfigurationSupport {

@Autowired
private CustomizedInterceptor customizedInterceptor;

@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customizedInterceptor).addPathPatterns("/**");
}
}

Exception处理

对Request Mapping Handler方法抛出的异常进行处理。

  • ExceptionHandler
    • Controller层异常处理
    • ControllerAdvice全局异常处理

Reference