SpringMVC
DispatcherServlet 初始化时机
默认情况下,DispatcherServlet在Tomcat服务器第一次使用到它时初始化,可以通过参数修改这个策略。
//方法参数默认为-1,大于0表示容器启动后立即初始化DispatcherServlet
DispatcherServletRegistrationBean.setLoadOnStartup(int);
配置文件中对应的参数为
spring.mvc.servlet.load-on-startup
DispatcherServlet 初始化做了什么
可以在 DispatcherServlet.onRefresh(..) 方法中看到其具体实现
public class DispatcherServlet extends FrameworkServlet {
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); //文件上传相关
initLocaleResolver(context); //初始化本地化信息,国家,地区,语言等
initThemeResolver(context);
initHandlerMappings(context); //初始化请求路径与控制器方法的映射关系
initHandlerAdapters(context); //请求处理逻辑的适配器,适配不同形式的控制器方法,最常见的就是直接将逻辑写在Controller的方法中
initHandlerExceptionResolvers(context); //控制器异常解析(统一异常处理?)
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}
RequestMappingHandlerMapping 基本用途
根据@RequestMapping及其衍生注解实现路径映射
- 找到当前路径下所有的控制器类
- 找到控制器类中所有被
@RequestMapping等注解标注的方法 - 记录这些注解的值路径与对应的方法,生成映射关系,存储在
RequestMappingHandlerMapping中
//可以通过这个方法来获取映射结果
//RequestMappingInfo 封装了请求参数等信息
//HandlerMethod 封装了控制器方法信息
Map<RequestMappingInfo, HandlerMethod> handlerMethods = RequestMappingHandlerMapping.getHandlerMethods();
//请求来了,获取控制器方法,返回处理器执行链对象,此对象除了包含 HandlerMethod,还包含了过滤器(如果有)
HandlerExecutionChain chain = RequestMappingHandlerMapping.getHandler(HttpServletRequest);
RequestMappingHandlerAdapter 基本用途
调用用 @RequestMapping 标注的控制器方法
//核心:调用这个方法,其内部最终会通过反射调用控制器方法
RequestMappingHandlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod)chain.getHandler());
自定义参数和返回值处理器
Controller中请求方法的参数是由参数解析器来完成解析的,位置如下
public class RequestMappingHandlerAdapter
//获取所有的参数解析器
public List<HandlerMethodArgumentResolver> getArgumentResolvers() {
return (this.argumentResolvers != null ? this.argumentResolvers.getResolvers() : null);
}
//可以通过此方法加入自定义的参数解析器,所有参数解析器都应该实现 HandlerMethodArgumentResolver 接口
public void setCustomArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
this.customArgumentResolvers = argumentResolvers;
}
//可以通过此方法加入自定义的返回值处理器,所有返回值处理器都应该实现 HandlerMethodReturnValueHandler 接口
public void setCustomReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {
this.customReturnValueHandlers = returnValueHandlers;
}
}
实现参数解析器接口
public interface HandlerMethodArgumentResolver {
//只有此方法返回值为true,解析器才会继续调用下面的 resolveArgument 方法正式解析参数
boolean supportsParameter(MethodParameter parameter);
//编写解析的逻辑,并把解析后得到的参数值返回
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
实现返回值处理器接口
public interface HandlerMethodReturnValueHandler {
//判断是否需要处理返回值
boolean supportsReturnType(MethodParameter returnType);
//编写处理返回值的具体逻辑,可以通过webRequest拿到原始的请求,响应对象,再通过响应对象将返回值写入输出流
//webRequest.getNativeResponse(HttpServletResponse.class)
//默认情况下,即使已经通过这里将返回值写入了输出流,SpringMVC仍然会进行视图解析的步骤,可以通过调用 mavContainer.setRequestHandled(true) 告知请求已经处理完毕
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
关于@ControllerAdvice
控制器增强(和AOP无关),可以配合以下三种注解使用
- @ExceptionHandler:统一异常处理
- @ModelAttribute:被此注解标注的方法,其返回值会作为模型数据补充到控制器的执行过程中
- @InitBinder:自定义类型转换器,其来源有两个
- @ControllerAdvice 中 @InitBinder 标注的方法,由
RequestMappingHandlerAdapter在初始化时解析并记录 - @Controller 中 @InitBinder 标注的方法,由
RequestMappingHandlerAdapter在控制器方法首次执行时解析并记录
- @ControllerAdvice 中 @InitBinder 标注的方法,由
控制器方法执行流程
核心是:ServletInvocableHandlerMethod,需要以下几个组件共同参与
1、数据绑定与类型转换 WebDataBinderFactory
2、解析参数名称 ParameterNameDiscoverer
3、参数解析器 HandlerMethodArgumentResolverComposite
@RequestParam("name")
@RequestParam(name = "xxx", defaultValue = "${JAVA_HOME}"):可以获取Spring提供的参数
@PathVariable("id")
@RequestHeader("Content-Type")
@CookieValue
@Value("${JAVA_HOME}")
@ModelAttribute User user:可以省略@ModelAttribute
@RequestBody
4、返回值处理器 HandlerMethodReturnValueHandlerComposite
@ControllerAdvice 配合 ResponseBodyAdvice接口,对响应做增强
@ControllerAdvice
public class MyControllerAdvice implements ResponseBodyAdvice<Object> {
//判断是否满足条件
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return false;
}
//Object body: 接口的原始响应体
//MethodParameter returnType:接口的方法信息
//return 包装后的响应体
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return null;
}
}

浙公网安备 33010602011771号