url映射(HandlerMapping)的执行适配器
在DispatcherServlet
类中的initHandlerAdapters()
初始化handlerAdapters
。
SpringMVC默认有三个
HttpRequestHandlerAdapter
, 该HttpRequestHandler
接口的适配执行器SimpleControllerHandlerAdapter
, 该Controller
接口的适配执行器RequestMappingHandlerAdapter
,处理@RequestMapping
的适配执行器
先看看代码块,如果需要自定义,尽量将默认的也注入到容器中
public class DispatcherServlet extends FrameworkServlet {
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// 查找容器中所有的 HandlerAdapter类型的Bean
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// 排序
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
/* 只从容器中获取 BeanName = handlerAdapter HandlerAdapter类型的Bean */
HandlerAdapter ha = context.getBean("handlerAdapter", HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
}
}
/**
* 没有自定义 使用默认的
*/
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
}
}
}
getDefaultStrategies(context, Class)
根据Class类型创建默认的实例,依靠Web容器的createBean
创建实例
defaultStrategies 这里有一个静态变量,保存着SpringMVC的默认配置,查看默认配置文件
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
/**
* 重点关注下这里 SpringMVC 的默认策略
*/
String value = defaultStrategies.getProperty(key);
if (value != null) {
/**
* 以 逗号 分割
*/
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
for (String className : classNames) {
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
/**
* 这里是用 Web容器去创建实例
* 默认是多实例的(scope = provided)
*/
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
}
catch (LinkageError err) {
}
}
return strategies;
}
else {
return new LinkedList<>();
}
}
createDefaultStrategy(context, clazz)
调用 Web容器的createBean
创建Bean
1:HttpRequestHandlerAdapter
处理 HttpRequestHandler
接口的 url映射
public class HttpRequestHandlerAdapter implements HandlerAdapter {
/**
* 是否支持该 handler 执行 ( 判断 handler 是否是 实现了 HttpRequestHandler接口)
* @param handler
* @return 返回true 代表应用该适配器执行url映射处理
*/
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
/**
* 执行 {@link HttpRequestHandler#handleRequest(HttpServletRequest, HttpServletResponse)}
*/
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
/**
* 获取上次修改
* @return
*/
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
2:SimpleControllerHandlerAdapter
处理 Controller
接口的 url映射
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
/**
* 是否支持该 handler 执行 ( 判断 handler 是否是 实现了 Controller接口)
* @return 返回true 代表应用该适配器执行url映射处理
*/
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
/**
* 执行 {@link Controller#handleRequest(HttpServletRequest, HttpServletResponse)}
*/
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
/**
* 获取上次修改
* @return
*/
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
3:RequestMappingHandlerAdapter
处理 @RequestMapping
接口的 url映射 最为常用的
一个请求通过 RequestMappingHandlerAdapter
执行的大致过程。
1:通过请求的url
获取执行目标方法(HandlerMapping
)。
2:通过(HandlerMapping
)获取到适配的HandlerAdapter,此处是(RequestMappingHandlerAdapter
)。
3:通过目标方法参数类型,获取适配的参数解析器(HandlerMethodArgumentResolver
),进行参数赋值。
4:通过目标方法的返回值类型,获取到适配的返回数据处理器(HandlerMethodReturnValueHandler
)
5:通过返回数据类型获取到适配的消息转换器(HttpMessageConverter
),响应数据。
底层源码分析
重点关注它实现的afterPropertiesSet
接口下的Bean实例化成功的初始化方法。
说明:此处就不以SpringMVC在DispatcherServlet.initHandlerAdapters
方法初始化HandlerAdapter
分析了,因为我们开发中都是用SpringBoot(自动装配版开发的)。
直接看到@EnableWebMvc
注解中导入的类DelegatingWebMvcConfiguration
的父类WebMvcConfigurationSupport
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
/**
* 向容器注入一个 Bean @Bean
* @return
*/
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
/**
* 创建 RequestMappingHandlerAdapter 实例
* new RequestMappingHandlerAdapter()
*/
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(mvcContentNegotiationManager());
/**
* 设置 消息转换器(MessageConverters)
*/
adapter.setMessageConverters(getMessageConverters());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
/**
* 设置自定义的 参数解析器(ArgumentResolver)
* {@link WebMvcConfigurer#addArgumentResolvers(List)}
*/
adapter.setCustomArgumentResolvers(getArgumentResolvers());
/**
* 设置自定义的 返回值处理器(ReturnValueHandler)
* {@link WebMvcConfigurer#addReturnValueHandlers(List)}
*/
adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
if (jackson2Present) {
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
/**
* 以下是 异步支持
*/
AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
configureAsyncSupport(configurer);
if (configurer.getTaskExecutor() != null) {
adapter.setTaskExecutor(configurer.getTaskExecutor());
}
if (configurer.getTimeout() != null) {
adapter.setAsyncRequestTimeout(configurer.getTimeout());
}
/**
* {@link Callable}
*/
adapter.setCallableInterceptors(configurer.getCallableInterceptors());
/**
* {@link DeferredResult}
*/
adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
return adapter;
}
}
关注下adapter.setMessageConverters(getMessageConverters())
获取消息转换器,然后赋值,这里面有点东西。
一开始使用 我们配置的WebMvcConfigurer.configureMessageConverters
如果它不返回空,则直接应用这些消息转换器,不再使用默认的消息转换器。
我们可以基于这一点,直接定制化SpringMVC的消息转换器。
如果只是想添加一个消息转换器,则使用WebMvcConfigurer.extendMessageConverters
。
再说下,如果没有必要,请勿使用WebMvcConfigurer.configureMessageConverters
该配置,经量使用SpringMVC默认的配置项。
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected final List<HttpMessageConverter<?>> getMessageConverters() {
/* 一开始创建 肯定为 null */
if (this.messageConverters == null) {
this.messageConverters = new ArrayList<>();
/**
* 这里是调用
* {@link WebMvcConfigurer#configureMessageConverters(List)}
*/
configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
/* 如果为空 使用默认的 */
addDefaultHttpMessageConverters(this.messageConverters);
}
/**
* 这里是调用 拓展WebMvcConfigurer
* {@link WebMvcConfigurer#extendMessageConverters(List)}
*/
extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}
}
RequestMappingHandlerAdapter.afterPropertiesSet
Bean实例化初始化方法,参数解析,返回值解析,都有各自的包装类。
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Override
public void afterPropertiesSet() {
/**
* 初始化 @ControllerAdvice 缓存
* 从容器中获取 所有 @ControllerAdvice 的Bean 缓存到当前实例中
*/
initControllerAdviceCache();
/**
* 参数解析器赋值
*/
if (this.argumentResolvers == null) {
/**
* 获取默认的 和 自定义的
*/
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
/* 包装下 */
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
/**
* 返回值处理器赋值
*/
if (this.returnValueHandlers == null) {
/**
* 获取默认的 和 自定义的
*/
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
/* 包装下 */
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
}
在SpringBoot中,SpringMVC是这样子装配的,在WebMvcAutoConfiguration
内部类EnableWebMvcConfiguration
。
所在目录包 org.springframework.boot.autoconfigure.web.servlet
总结
RequestMappingHandlerAdapter最终都是Spring容器创建的实例,而且它提供了很多set方法,我们可以在开发中,通过applicationContext获取到此Bean,动态的修改它的属性。
例如:
- 删除掉它一些默认的参数解析器,消息转换器之类的。
- 因为它的解析器,处理器都是List列表,我们可以将我们自定义的添加到他的前面。
- 比如@RequestParam注解,为空报错提示修改。
- 最重要的就是,要深入理解SpringMVC的源码,我们就可以定制化SpringMVC。