介面定義
/**
* Interface to be implemented by objects that define a mapping between
* requests and handler objects.
*/
public interface HandlerMapping {
//根據request獲取處理鏈
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
複製程式碼
以RequestMappingHandlerMapping為例來講
RequestMappingHandlerMapping初始化過程
定義: 請求路徑-處理過程對映管理
打個比方就是根據你的http請求的路徑得到可以處理的handler(你的Controller方法)
先看下他的繼承關係
看到3個Spring的生命週期介面
-
ServletContextAware:儲存ServletContext
#org.springframework.web.context.support.WebApplicationObjectSupport @Override public final void setServletContext(ServletContext servletContext) { if (servletContext != this.servletContext) { //儲存ServletContext this.servletContext = servletContext; if (servletContext != null) { //空實現 initServletContext(servletContext); } } } 複製程式碼
-
ApplicationContext:儲存Spring上下文
@Override public final void setApplicationContext(ApplicationContext context) throws BeansException { ... //儲存SpringMVC上下文 this.applicationContext = context; //儲存資源訪問器 this.messageSourceAccessor = new MessageSourceAccessor(context); //空實現 initApplicationContext(context); ... } 複製程式碼
-
InitlizingBean:初始化對映關係
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping //1. @Override public void afterPropertiesSet() { if (this.useRegisteredSuffixPatternMatch) { this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions()); } super.afterPropertiesSet(); } //4. @Override protected boolean isHandler(Class<?> beanType) { return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) || (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null)); } //6. @Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { RequestMappingInfo info = null; RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class); if (methodAnnotation != null) { //組裝對映資訊 RequestCondition<?> methodCondition = getCustomMethodCondition(method); info = createRequestMappingInfo(methodAnnotation, methodCondition); RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); if (typeAnnotation != null) { RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType); info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); } } return info; } #org.springframework.web.servlet.handler.AbstractHandlerMethodMapping //2. @Override public void afterPropertiesSet() { initHandlerMethods(); } //3. protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } //從容器中獲取所有object型別名 String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { //抽象,過濾(在RequestMappingHandlerMapping中根據Controller和RequestMapping註解過濾) if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){ //探測類中定義的handler方法 detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods()); } //5. protected void detectHandlerMethods(final Object handler) { Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); final Map<Method, T> mappings = new IdentityHashMap<Method, T>(); final Class<?> userType = ClassUtils.getUserClass(handlerType); //得到符合條件的handler方法 Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { @Override public boolean matches(Method method) { //抽象,得到對映資訊(如RequestMappingInfo) T mapping = getMappingForMethod(method, userType); if (mapping != null) { mappings.put(method, mapping); return true; } else { return false; } } }); //註冊handler對映關係 for (Method method : methods) { //儲存對映路徑和處理方法(還有跨域資訊) registerHandlerMethod(handler, method, mappings.get(method)); } } 複製程式碼
過程概括:
-
獲取所有object子類
-
根據條件過濾出handle處理類
-
解析handle類中定義的處理方法
-
註冊對映關係
public void register(T mapping, Object handler, Method method) { try { //儲存handler和處理方法 HandlerMethod handlerMethod = createHandlerMethod(handler, method); ... //儲存對映路徑和HandlerMethod this.mappingLookup.put(mapping, handlerMethod); //解析@CrossOrigin配置(跨域用) CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); //儲存跨域資訊 if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } //儲存對映關係 this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name)); } ... 複製程式碼
}
## getHandler()實現
```java
#org.springframework.web.servlet.handler.AbstractHandlerMapping
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//抽象,呼叫子類實現得到一個handler(可以是任一物件,需要通過HandleAdapter來解析)
//RequestMappingInfoHandlerMapping中具體實現就是匹配請求路徑和RequestMapping註解
Object handler = getHandlerInternal(request);
...
//包裝handle成HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
//如果是跨域請求 則根據@CrossOrigin配置新增前置Intercept
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
#org.springframework.web.servlet.handler.AbstractHandlerMethodMapping
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//得到對映路徑
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
...
try {
//根據對映路徑獲取HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
...
}
複製程式碼