SpringMVC源碼解析系列3-HandleMapping

接口定義

/** * 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爲例來說java

RequestMappingHandlerMapping初始化過程

定義: 請求路徑-處理過程映射管理web

打個比方就是根據你的http請求的路徑獲得能夠處理的handler(你的Controller方法)spring

先看下他的繼承關係跨域

RequestMappingHandlerMapping

看到3個Spring的生命週期接口bash

  1. ServletContextAware:保存ServletContextmvc

    #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);
    		}
    	}
    }
    複製代碼
  2. ApplicationContext:保存Spring上下文app

    @Override
    public final void setApplicationContext(ApplicationContext context) throws BeansException {
    ...
      //保存SpringMVC上下文
      this.applicationContext = context;
      //保存資源訪問器
      this.messageSourceAccessor = new MessageSourceAccessor(context);
      //空實現
      initApplicationContext(context);
    	...
    }
    複製代碼
  3. InitlizingBean:初始化映射關係cors

    #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));
    	}
    }
    複製代碼

過程歸納:ide

  1. 獲取全部object子類ui

  2. 根據條件過濾出handle處理類

  3. 解析handle類中定義的處理方法

  4. 註冊映射關係

    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);
 }
 ...
}
複製代碼
相關文章
相關標籤/搜索