欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springmvc組件中的HandlerMapping解析

 更新時間:2023年09月09日 09:52:03   作者:還沒禿的小菜雞  
這篇文章主要介紹了springmvc九大組件中的HandlerMapping解析,HandlerMapping表示的是一個URL與一個Handler(可以簡單的理解為Controller中有@RequestMapping注解的方法)之間的映射關系,需要的朋友可以參考下

HandlerMapping

HandlerMapping在Spring MVC框架的jar包下面,他是處理映射器,為用戶發(fā)送的請求找到合適的Handler Adapter,它將會把請求映射為HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象、多個HandlerInterceptor攔截器)對象,同時通過這種策略模式,很容易添加新的映射策略。SpringMVC在請求到handler處理器的分發(fā)這步就是通過HandlerMapping模塊解決的,handlerMapping還處理攔截器,同時Spring MVC也提供了一系列HandlerMapping的實現(xiàn),根據(jù)一定的規(guī)則選擇controller。

public interface HandlerMapping {
   // 返回請求的一個處理程序handler和攔截器interceptors
   @Nullable
   HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

HandlerMapping執(zhí)行流程如下:

  • 初始化流程:DispatcherServlet——>initHandlerMappings(context)
private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    //默認為true,可通過DispatcherServlet的init-param參數(shù)進行設置
    if (this.detectAllHandlerMappings) {
        //在ApplicationContext中找到所有的handlerMapping, 包括父級上下文
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            //排序,可通過指定order屬性進行設置,order的值為int型,數(shù)越小優(yōu)先級越高
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    } else {
        try {
            //從ApplicationContext中取id(或name)="handlerMapping"的bean,此時為空
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            // 將hm轉(zhuǎn)換成list,并賦值給屬性handlerMappings
            this.handlerMappings = Collections.singletonList(hm);
        } catch (NoSuchBeanDefinitionException ex) {
        }
    }
    //如果沒有自定義則使用默認的handlerMappings
    //默認的HandlerMapping在DispatcherServlet.properties屬性文件中定義,
    // 該文件是在DispatcherServlet的static靜態(tài)代碼塊中加載的
    // 默認的是:BeanNameUrlHandlerMapping和RequestMappingHandlerMapping
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);//默認策略
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}
  1. 如果緩存中存在,則從緩存中獲取,并進行排序
  2. 從ApplicationContext中取id(或name)="handlerMapping"的bean
  3. 如果沒有自定義則使用默認的handlerMappings
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName();//HandlerMappings
    //獲取HandlerMappings為key的value值,defaultStrategies在static塊中讀取DispatcherServlet.properties
    String value = defaultStrategies.getProperty(key);
    if (value != null) {
        //逗號,分割成數(shù)組
        String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
        List<T> strategies = new ArrayList<>(classNames.length);
        for (String className : classNames) {
            try {
                //反射加載并存儲strategies
                Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                //通過容器創(chuàng)建bean 觸發(fā)后置處理器    
                Object strategy = createDefaultStrategy(context, clazz);
                strategies.add((T) strategy);
            }
     。。。
        }
        return strategies;
    }
    else {
        return new LinkedList<>();
    }
}
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
    //通過容器創(chuàng)建bean
    return context.getAutowireCapableBeanFactory().createBean(clazz);
}
  • 獲取HandlerMappings為key的value值,defaultStrategies在static塊中讀取DispatcherServlet.properties
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
   org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
   org.springframework.web.servlet.function.support.RouterFunctionMapping
  • 執(zhí)行service方法流程:DispatcherServlet——>doDispatch()——>getHandler(request)——>getHandlerExecutionChain(handler, request)——>new HandlerExecutionChain(handler))——>chain.addInterceptor(interceptor)

HandlerMapping是處理器映射器,根據(jù)請求找到處理器Handler,但并不是簡單的返回處理器,而是將處理器和攔截器封裝,形成一個處理器執(zhí)行鏈(HandlerExecuteChain)。

AbstractHandlerMapping

獲取處理器執(zhí)行鏈的過程在AbstractHandlerMapping中的getHandler方法

  • 先看看初始化過程
protected void initApplicationContext() throws BeansException {
	//模板方法,用于給子類提供一個添加Interceptors的入口。
	extendInterceptors(this.interceptors);
	//將SpringMvc容器和父容器中所有的MappedInterceptor類型的Bean添加到mappedInterceptors的屬性
	detectMappedInterceptors(this.mappedInterceptors);
    //用于初始化Interceptor,將Interceptors屬性里所包含的對象按類型添加到mappedInterceptors和adaptedInterceptors.
	initInterceptors();
}

AbstractHandlerMapping通過initApplicationContext()方法進行自動初始化,它的創(chuàng)建其實就是初始化上面三個interceptor,其一般是由父類執(zhí)行ApplicationContextAware#setApplicationContext()方法間接調(diào)用,主要是獲取springmvc上下文中的攔截器集合MappedInterceptor。

  • getHandler() 獲取處理鏈對象
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	//getHandlerInternal(request)方法為抽象方法,供子類實現(xiàn)
	//獲取到的handler對象一般為bean/HandlerMethod
	Object handler = getHandlerInternal(request);
	//上述找不到則使用默認的處理類,沒有設定則返回null,則會返回前臺404錯誤
	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);
	}
	//創(chuàng)建處理鏈對象
	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
	//針對cros跨域請求的處理,此處就不分析了
	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;
}
//針對HandlerMethod的獲取
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	//獲取訪問的路徑,一般類似于request.getServletPath()返回不含contextPath的訪問路徑
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	//獲取讀鎖
	this.mappingRegistry.acquireReadLock();
	try {
		//獲取HandlerMethod作為handler對象,這里涉及到路徑匹配的優(yōu)先級
		//優(yōu)先級:精確匹配>最長路徑匹配>擴展名匹配
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		//HandlerMethod內(nèi)部含有bean對象,其實指的是對應的Controller
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		//釋放讀鎖
		this.mappingRegistry.releaseReadLock();
	}
}
//針對beanName的獲取
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	//從handlerMap查找路徑對應的beanName
	Object handler = lookupHandler(lookupPath, request);
	if (handler == null) {
		// We need to care for the default handler directly, since we need to
		// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
		Object rawHandler = null;
		if ("/".equals(lookupPath)) {
			rawHandler = getRootHandler();
		}
		if (rawHandler == null) {
			rawHandler = getDefaultHandler();
		}
		if (rawHandler != null) {
			// Bean name or resolved handler?
			if (rawHandler instanceof String) {
				String handlerName = (String) rawHandler;
				rawHandler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(rawHandler, request);
			handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
		}
	}
	return handler;
}

HandlerMapping是通過getHandler方法來獲取處理器Handler和攔截器Interceptors的,AbstractHandlerMapping實現(xiàn)獲取handler。

在獲取handler對象時是由其子類實現(xiàn)的,分別為AbstractHandlerMethodMapping,AbstractUrlHandlerMapping

  • AbstractHandlerMethodMapping當bean被注入到容器后會執(zhí)行一系列的初始化過程,用于注解@Controller,@RequestMapping來定義controller。
//容器啟動時會運行此方法,完成handlerMethod的注冊操作  
@Override  
public void afterPropertiesSet() {  
	initHandlerMethods();  
}
protected void initHandlerMethods() {
   //獲取上下文中所有bean的name,不包含父容器
   for (String beanName : getCandidateBeanNames()) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
         processCandidateBean(beanName);
      }
   }
   //日志記錄HandlerMethods的總數(shù)量
   handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
   Class<?> beanType = null;
   try {
      //根據(jù)name找出bean的類型
      beanType = obtainApplicationContext().getType(beanName);
   }
   catch (Throwable ex) {
      // An unresolvable bean type, probably from a lazy bean - let's ignore it.
      if (logger.isTraceEnabled()) {
         logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
      }
   }
   //處理Controller和RequestMapping
   if (beanType != null && isHandler(beanType)) {
      detectHandlerMethods(beanName);
   }
}
//整個controller類的解析過程
protected void detectHandlerMethods(Object handler) {
   //根據(jù)name找出bean的類型
   Class<?> handlerType = (handler instanceof String ?
         obtainApplicationContext().getType((String) handler) : handler.getClass());
   if (handlerType != null) {
      //獲取真實的controller,如果是代理類獲取父類
      Class<?> userType = ClassUtils.getUserClass(handlerType);
      //對真實的controller所有的方法進行解析和處理  key為方法對象,T為注解封裝后的對象RequestMappingInfo
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> {
               try {
                  // 調(diào)用子類RequestMappingHandlerMapping的getMappingForMethod方法進行處理,
                  // 即根據(jù)RequestMapping注解信息創(chuàng)建匹配條件RequestMappingInfo對象
                  return getMappingForMethod(method, userType);
               }
               catch (Throwable ex) {
                  throw new IllegalStateException("Invalid mapping on handler class [" +
                        userType.getName() + "]: " + method, ex);
               }
            });
      if (logger.isTraceEnabled()) {
         logger.trace(formatMappings(userType, methods));
      }
      methods.forEach((method, mapping) -> {
         //找出controller中可外部調(diào)用的方法
         Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
         //注冊處理方法
         registerHandlerMethod(handler, invocableMethod, mapping);
      });
   }
}
后續(xù)主要是通過RequestMappingHandlerMapping  完成:
  1. 通過方法isHandler(beanType)判斷是否處理Controller和RequestMapping
  2. 調(diào)用子類RequestMappingHandlerMapping的getMappingForMethod方法進行處理,即根據(jù)RequestMapping注解信息創(chuàng)建匹配條件RequestMappingInfo對象getMappingForMethod(method, userType);
  3. 注冊處理方法registerHandlerMethod(handler, invocableMethod, mapping)
  • AbstractUrlHandlerMapping是AbstractHandlerMapping的子類,實現(xiàn)針對beanName注冊為handler對象。
//注冊url和Bean的map,將具體的Handler注入到url對應的map中
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
   Assert.notNull(urlPath, "URL path must not be null");
   Assert.notNull(handler, "Handler object must not be null");
   Object resolvedHandler = handler;
   // Eagerly resolve handler if referencing singleton via name.
   // 不是懶加載,默認為false,即不是,通過配置SimpleUrlHandlerMapping屬性lazyInitHandlers的值進行控制
   // 如果不是懶加載并且handler為單例,即從上下文中查詢實例處理,此時resolvedHandler為handler實例對象;
   // 如果是懶加載或者handler不是單例,即resolvedHandler為handler邏輯名
   if (!this.lazyInitHandlers && handler instanceof String) {
      String handlerName = (String) handler;
      ApplicationContext applicationContext = obtainApplicationContext();
      // 如果handler是單例,通過bean的scope控制
      if (applicationContext.isSingleton(handlerName)) {
         resolvedHandler = applicationContext.getBean(handlerName);
      }
   }
   Object mappedHandler = this.handlerMap.get(urlPath);
   if (mappedHandler != null) {
      if (mappedHandler != resolvedHandler) {
         throw new IllegalStateException(
               "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
               "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
      }
   }
   else {
      if (urlPath.equals("/")) {
         if (logger.isTraceEnabled()) {
            logger.trace("Root mapping to " + getHandlerDescription(handler));
         }
         //"/"-->設置為roothandler
         setRootHandler(resolvedHandler);
      }
      else if (urlPath.equals("/*")) {
         if (logger.isTraceEnabled()) {
            logger.trace("Default mapping to " + getHandlerDescription(handler));
         }
         //對"/*"的匹配設置默認的handler
         setDefaultHandler(resolvedHandler);
      }
      else {
         //其余的路徑綁定關系則存入handlerMap
         this.handlerMap.put(urlPath, resolvedHandler);
         if (logger.isTraceEnabled()) {
            logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
         }
      }
   }
}

RequestMappingHandlerMapping

  • 通過方法isHandler(beanType)判斷是否處理Controller和RequestMapping
@Override
protected boolean isHandler(Class<?> beanType) {
   //獲取@Controller和@RequestMapping
   return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
         AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
public static boolean hasAnnotation(AnnotatedElement element, Class<? extends Annotation> annotationType) {
		// Shortcut: directly present on the element, with no merging needed?
		if (AnnotationFilter.PLAIN.matches(annotationType) ||
				AnnotationsScanner.hasPlainJavaAnnotationsOnly(element)) {
			return element.isAnnotationPresent(annotationType);
		}
		// Exhaustive retrieval of merged annotations...
		return findAnnotations(element).isPresent(annotationType);
	}
  • requestMapping封裝成RequestMappingInfo對象
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
   RequestMappingInfo info = createRequestMappingInfo(method);
   if (info != null) {
      //解析方法所在類上的requestMapping
      RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
      if (typeInfo != null) {
         info = typeInfo.combine(info);//合并類和方法上的路徑,比如Controller類上有@RequestMapping("/demo"),方法的@RequestMapping("/demo1"),結(jié)果為"/demo/demo1"
      }
      String prefix = getPathPrefix(handlerType);//合并前綴
      if (prefix != null) {
         info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
      }
   }
   return info;
}
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		//找到方法上的RequestMapping注解
		RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
		//獲取自定義的類型條件(自定義的RequestMapping注解)
		RequestCondition<?> condition = (element instanceof Class ?
				getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
		return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
	}
  • 注冊處理方法registerHandlerMethod(handler, invocableMethod, mapping)
public void register(T mapping, Object handler, Method method) {
   // Assert that the handler method is not a suspending one.
   if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
      throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
   }
   this.readWriteLock.writeLock().lock();
   try {
      //beanName和method封裝成HandlerMethod對象
      HandlerMethod handlerMethod = createHandlerMethod(handler, method);
      //驗證RequestMappingInfo是否有對應不同的method,有則拋出異常
      validateMethodMapping(handlerMethod, mapping);
      //RequestMappingInfo和handlerMethod綁定
      this.mappingLookup.put(mapping, handlerMethod);
      List<String> directUrls = getDirectUrls(mapping);//可以配置多個url
      for (String url : directUrls) {
         //url和RequestMappingInfo綁定   可以根據(jù)url找到RequestMappingInfo,再找到handlerMethod
         this.urlLookup.add(url, mapping);
      }
      String name = null;
      if (getNamingStrategy() != null) {
         name = getNamingStrategy().getName(handlerMethod, mapping);
         addMappingName(name, handlerMethod);//方法名和Method綁定
      }
      CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
      if (corsConfig != null) {
         this.corsLookup.put(handlerMethod, corsConfig);
      }
      this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
   }
   finally {
      this.readWriteLock.writeLock().unlock();
   }
}

BeanNameUrlHandlerMapping

public class HelloController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {
        ModelAndView mav = new ModelAndView("index");
        mav.addObject("message", "默認的映射處理器示例");
        return mav;
    }
<bean id="resourceView"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>
<bean id="/name.do" class="com.zy.mvc.controller.HelloController"></bean>
//向上繼承自ApplicationObjectSupport實現(xiàn)ApplicationContextAware接口
public abstract class ApplicationObjectSupport implements ApplicationContextAware {
    protected final Log logger = LogFactory.getLog(this.getClass());
    @Nullable
    private ApplicationContext applicationContext;
    ...
    public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
        if (context == null && !this.isContextRequired()) {
            this.applicationContext = null;
            this.messageSourceAccessor = null;
        } else if (this.applicationContext == null) {
            if (!this.requiredContextClass().isInstance(context)) {
                throw new ApplicationContextException("Invalid application context: needs to be of type [" + this.requiredContextClass().getName() + "]");
            }
            this.applicationContext = context;
            this.messageSourceAccessor = new MessageSourceAccessor(context);
            this.initApplicationContext(context);//模板方法,調(diào)子類
        } else if (this.applicationContext != context) {
            throw new ApplicationContextException("Cannot reinitialize with different application context: current one is [" + this.applicationContext + "], passed-in one is [" + context + "]");
        }
    }
    ...
}
	//AbstractDetectingUrlHandlerMapping
    @Override
    public void initApplicationContext() throws ApplicationContextException {
        super.initApplicationContext();//加載攔截器
        // 處理url和bean name,具體注冊調(diào)用父類AbstractUrlHandlerMapping類完成
        detectHandlers();
    }
    //建立當前ApplicationContext中controller和url的對應關系
    protected void detectHandlers() throws BeansException {
        // 獲取應用上下文
        ApplicationContext applicationContext = obtainApplicationContext();
        //獲取ApplicationContext中的所有bean的name(也是id,即@Controller的屬性值)
        String[] beanNames = (this.detectHandlersInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext,Object.class) : applicationContext.getBeanNamesForType(Object.class));
        //遍歷所有beanName
        for (String beanName : beanNames) {
            // 通過模板方法模式調(diào)用BeanNameUrlHandlerMapping子類處理
            String[] urls = determineUrlsForHandler(beanName);//判斷是否以/開始
            if (!ObjectUtils.isEmpty(urls)) {
                //調(diào)用父類AbstractUrlHandlerMapping將url與handler存入map
                registerHandler(urls, beanName);
            }
        }
    }
    protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
        Assert.notNull(urlPath, "URL path must not be null");
        Assert.notNull(handler, "Handler object must not be null");
        Object resolvedHandler = handler;
        // Eagerly resolve handler if referencing singleton via name.
        if (!this.lazyInitHandlers && handler instanceof String) {
            String handlerName = (String) handler;
            ApplicationContext applicationContext = obtainApplicationContext();
            if (applicationContext.isSingleton(handlerName)) {
                resolvedHandler = applicationContext.getBean(handlerName);
            }
        }
        //已存在且指向不同的Handler拋異常
        Object mappedHandler = this.handlerMap.get(urlPath);
        if (mappedHandler != null) {
            if (mappedHandler != resolvedHandler) {
                throw new IllegalStateException(
                        "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
                                "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
            }
        }
        else {
            if (urlPath.equals("/")) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Root mapping to " + getHandlerDescription(handler));
                }
                setRootHandler(resolvedHandler);//設置根處理器,即請求/的時候
            }
            else if (urlPath.equals("/*")) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Default mapping to " + getHandlerDescription(handler));
                }
                setDefaultHandler(resolvedHandler);//默認處理器
            }
            else {
                this.handlerMap.put(urlPath, resolvedHandler);//注冊進map
                if (logger.isTraceEnabled()) {
                    logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
                }
            }
        }
    }

處理器bean的id/name為一個url請求路徑,前面有"/"; 如果多個url映射同一個處理器bean,那么就需要定義多個bean,導致容器創(chuàng)建多個處理器實例,占用內(nèi)存空間; 處理器bean定義與url請求耦合在一起。

SimpleUrlHandlerMapping

間接實現(xiàn)了org.springframework.web.servlet.HandlerMapping接口,直接實現(xiàn)該接口的是org.springframework.web.servlet.handler.AbstractHandlerMapping抽象類,映射Url與請求handler bean。支持映射bean實例和映射bean名稱

public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
    // 存儲url和bean映射
    private final Map<String, Object> urlMap = new LinkedHashMap<>();
    // 注入property的name為mappings映射
    public void setMappings(Properties mappings) {
        CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
    }
    // 注入property的name為urlMap映射
    public void setUrlMap(Map<String, ?> urlMap) {
        this.urlMap.putAll(urlMap);
    }
    public Map<String, ?> getUrlMap() {
        return this.urlMap;
    }
    // 實例化本類實例入口
    @Override
    public void initApplicationContext() throws BeansException {
        // 調(diào)用父類AbstractHandlerMapping的initApplicationContext方法,只要完成攔截器的注冊
        super.initApplicationContext();
        // 處理url和bean name,具體注冊調(diào)用父類完成
        registerHandlers(this.urlMap);
    }
    // 注冊映射關系,及將property中的值解析到map對象中,key為url,value為bean id或name
    protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
        if (urlMap.isEmpty()) {
            logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
        } else {
            urlMap.forEach((url, handler) -> {
                // 增加以"/"開頭
                if (!url.startsWith("/")) {
                    url = "/" + url;
                }
                // 去除handler bean名稱的空格
                if (handler instanceof String) {
                    handler = ((String) handler).trim();
                }
                // 調(diào)用父類AbstractUrlHandlerMapping完成映射
                registerHandler(url, handler);
            });
        }
    }
}
  • SimpleUrlHandlerMapping類主要接收用戶設定的url與handler的映射關系,其實際的工作都是交由其父類來完成的
    • AbstractHandlerMapping 在創(chuàng)建初始化SimpleUrlHandlerMapping類時,調(diào)用其父類的initApplicationContext()方法,該方法完成攔截器的初始化
  • AbstractUrlHandlerMapping
    • 在創(chuàng)建初始化SimpleUrlHandlerMapping類時,調(diào)用AbstractUrlHandlerMapping類的registerHandler(urlPath,handler)方法

總結(jié)

在這里插入圖片描述

到此這篇關于springmvc組件中的HandlerMapping解析的文章就介紹到這了,更多相關springmvc組件HandlerMapping內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java實現(xiàn)BP神經(jīng)網(wǎng)絡MNIST手寫數(shù)字識別的示例詳解

    Java實現(xiàn)BP神經(jīng)網(wǎng)絡MNIST手寫數(shù)字識別的示例詳解

    這篇文章主要為大家詳細介紹了Java實現(xiàn)BP神經(jīng)網(wǎng)絡MNIST手寫數(shù)字識別的相關方法,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-01-01
  • Java實現(xiàn)一個簡單計算器

    Java實現(xiàn)一個簡單計算器

    這篇文章主要介紹了Java實現(xiàn)一個簡單計算器,文章我圍繞實現(xiàn)簡單計算器的相關代碼展現(xiàn)全文,具有一定的參考價值,需要的小伙伴可以參考一下,
    2022-01-01
  • java編程實現(xiàn)求質(zhì)數(shù)與因式分解代碼分享

    java編程實現(xiàn)求質(zhì)數(shù)與因式分解代碼分享

    這篇文章主要介紹了Java編程實現(xiàn)求質(zhì)數(shù)與因式分解代碼分享,對二者的概念作了簡單介紹(多此一舉,哈哈),都是小學數(shù)學老師的任務,然后分享了求解質(zhì)數(shù)和因式分解的Java代碼,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • 簡單捋捋@RequestParam 和 @RequestBody的使用

    簡單捋捋@RequestParam 和 @RequestBody的使用

    這篇文章主要介紹了簡單捋捋@RequestParam 和 @RequestBody的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • java返回前端實體類json數(shù)據(jù)時忽略某個屬性方法

    java返回前端實體類json數(shù)據(jù)時忽略某個屬性方法

    這篇文章主要給大家介紹了關于java返回前端實體類json數(shù)據(jù)時忽略某個屬性的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-08-08
  • 理解maven命令package、install、deploy的聯(lián)系與區(qū)別

    理解maven命令package、install、deploy的聯(lián)系與區(qū)別

    這篇文章主要介紹了理解maven命令package、install、deploy的聯(lián)系與區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • Java中stream的用法詳細解讀

    Java中stream的用法詳細解讀

    這篇文章主要介紹了Java中stream的用法詳細解讀,Stream 是 Java8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執(zhí)行非常復雜的查找、過濾和映射數(shù)據(jù)等操作,使用Stream API 對集合數(shù)據(jù)進行操作,就類似于使用SQL執(zhí)行的數(shù)據(jù)庫查詢,需要的朋友可以參考下
    2023-10-10
  • Java中JMM與volatile關鍵字的學習

    Java中JMM與volatile關鍵字的學習

    這篇文章主要介紹了通過實例解析JMM和Volatile關鍵字的學習,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2021-09-09
  • java封裝全局異常處理深入詳解

    java封裝全局異常處理深入詳解

    這篇文章主要為大家介紹了java封裝全局異常處理的深入詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Java迭代器與Collection接口超詳細講解

    Java迭代器與Collection接口超詳細講解

    Collection也稱集合,集合概述:集合是Java中提供的一種容器,可以用來存儲多個數(shù)據(jù)。Iterator(迭代器)不是一個集合,它是一種用于訪問集合的方法,可用于迭代 ArrayList 和 HashSet 等集合
    2022-07-07

最新評論