1.RequestMappingHandlerMapping的初始化流程
首先看下RequestMappingHandlerMapping的类图
RequestMappingHandlerMapping 实现了InitializingBean
在AbstractHandlerMethodMapping 中afterPropertiesSet(),会在容器注入的进去的时候执行。
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
// 注入扫描到handler的方法
this.mappingRegistry.register(mapping, handler, method);
}
由上图可知,RequestMappingHandlerMapping大致工作流程如下:
- RequestMappingHandlerMapping 向容器中注册的时候,检测到实现了 InitializingBean接口,容器去执行afterPropertiesSet(),在afterPropertiesSet中完成Controller中完成方法的映射
- initHandlerMethods 首先获取容器中全部的beanNames。
- 根据名字获取类,判断该类是不是要转换的类型
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
- 调用detectHandlerMethods开始做类型和路径映射转换
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
根据类型的方法做映射转换
- 此处应该是getMappingForMethod 是扩展点,可以继承RequestMappingHandlerMapping重写getMappingForMethod实现自己的映射规则。
例如:
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomerRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo requestMappingInfo = super.getMappingForMethod(method, handlerType);
if (requestMappingInfo != null) {
return requestMappingInfo;
}
return createCustomRequestMappingInfo(method);
}
private RequestMappingInfo createCustomRequestMappingInfo(Method method) {
RestMapping mapping = AnnotatedElementUtils.findMergedAnnotation(method, RestMapping.class);
if (mapping != null) {
return RequestMappingInfo.paths(Samples.URI_PREFIX_OF_API + mapping.value())
.methods(mapping.method())
.build();
}
return null;
}
}
如何通过RequestMappingHandlerMapping 找到请求对应的handler(方法)
spring mvc中,当请求到来的时候,会被统一到DispatcherServlet的doDispatch去执行。
看下doDispatch的部分代码,
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mappedHandler = getHandler(processedRequest); 就是根据请求获取处理的handler。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
此方法会根据注入到DispatcherServlet的RequestMappingHandlerMapping 集合来找到该请求对应的handler用于处理该请求。
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
RequestMappingHandlerMapping 如何注入到DispatcherServlet中
在DispatcherServlet初始化的时候,会调用内部的的一个onRefresh方法。最终会调用initHandlerMappings方法。
/**
* This implementation calls {@link #initStrategies}.
*/
@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);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
initHandlerMappings方法获取注入到容器中的全部的RequestMappingHandlerMapping,按照规则排序。赋值给本身的handlerMappings。当请求到来的时候会遍历handlerMappings,找到合适初始方法进行处理。如下是DispatcherServlet当请求达到的时候遍历handlerMappings。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
RequestMappingHandlerMapping 的注入容器
RequestMappingHandlerMapping 作为spring mvc 路由组件,起到了从路径到指定方法的转换作用。只有注入到容器中,在请求达到的时候,从容器中获取到RequestMappingHandlerMapping 在通过RequestMappingHandlerMapping获取到handler用于处理请求。
RequestMappingHandlerMapping的注入分为四种:
- 如果是基于xml配置的springmvc项目 在springmvc的配置文件中加入<mvc:annotation-driven/> ,在容器解析配置的文件的时候,会初始化RequestMappingHandlerMapping 并注入到容器中。
- 如果是基于注解的形式springmvc项目。可以使用@EnableWebMvc来初始化RequestMappingHandlerMapping并注入到容器中。具体实现请看
Spring注解开发 - 当基于spring boot 开发的时候 WebMvcAutoConfiguration 会自动加载web开发相关的配置。其中EnableWebMvcConfiguration 继承自DelegatingWebMvcConfiguration,DelegatingWebMvcConfiguration的内部原理 在Spring注解开发 已经做了阐述。EnableWebMvcConfiguration在WebMvcAutoConfiguration中一@Bean的形式被注入到容器中。因此RequestMappingHandlerMapping 此时会被创建注入到容器中。
- 自定义RequestMappingHandlerMapping,注入到容器中。可以采用xml的形式注入,也可以通过@Bean的形式注入;例如
@Bean
public RequestMappingHandlerMapping customRequestMappingHandlerMapping() {
CustomerRequestMappingHandlerMapping mappingHandlerMapping = new CustomerRequestMappingHandlerMapping();
mappingHandlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE);//设置排序
return mappingHandlerMapping;
}