亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring中的HandlerMapping執(zhí)行流程詳解

 更新時(shí)間:2023年08月31日 09:27:39   作者:還沒禿的小菜雞  
這篇文章主要介紹了Spring中的HandlerMapping執(zhí)行流程詳解,HandlerMapping在Spring MVC框架的jar包下面,他是處理映射器,為用戶發(fā)送的請求找到合適的Handler Adapter,它將會把請求映射為HandlerExecutionChain對象,需要的朋友可以參考下

HandlerMapping

HandlerMapping在Spring MVC框架的jar包下面,他是處理映射器,為用戶發(fā)送的請求找到合適的Handler Adapter,它將會把請求映射為HandlerExecutionChain對象(包含一個(gè)Handler處理器(頁面控制器)對象、多個(gè)HandlerInterceptor攔截器)對象,同時(shí)通過這種策略模式,很容易添加新的映射策略。

SpringMVC在請求到handler處理器的分發(fā)這步就是通過HandlerMapping模塊解決的,handlerMapping還處理攔截器,同時(shí)Spring MVC也提供了一系列HandlerMapping的實(shí)現(xiàn),根據(jù)一定的規(guī)則選擇controller。

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

HandlerMapping執(zhí)行流程如下

  • 初始化流程:DispatcherServlet——>initHandlerMappings(context)
private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    //默認(rèn)為true,可通過DispatcherServlet的init-param參數(shù)進(jìn)行設(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屬性進(jìn)行設(shè)置,order的值為int型,數(shù)越小優(yōu)先級越高
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    } else {
        try {
            //從ApplicationContext中取id(或name)="handlerMapping"的bean,此時(shí)為空
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            // 將hm轉(zhuǎn)換成list,并賦值給屬性handlerMappings
            this.handlerMappings = Collections.singletonList(hm);
        } catch (NoSuchBeanDefinitionException ex) {
        }
    }
    //如果沒有自定義則使用默認(rèn)的handlerMappings
    //默認(rèn)的HandlerMapping在DispatcherServlet.properties屬性文件中定義,
    // 該文件是在DispatcherServlet的static靜態(tài)代碼塊中加載的
    // 默認(rèn)的是:BeanNameUrlHandlerMapping和RequestMappingHandlerMapping
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);//默認(rèn)策略
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}
  • 如果緩存中存在,則從緩存中獲取,并進(jìn)行排序
  • 從ApplicationContext中取id(或name)="handlerMapping"的bean
  • 如果沒有自定義則使用默認(rèn)的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,但并不是簡單的返回處理器,而是將處理器和攔截器封裝,形成一個(gè)處理器執(zhí)行鏈(HandlerExecuteChain)。

AbstractHandlerMapping

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

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

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

  • getHandler() 獲取處理鏈對象
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	//getHandlerInternal(request)方法為抽象方法,供子類實(shí)現(xiàn)
	//獲取到的handler對象一般為bean/HandlerMethod
	Object handler = getHandlerInternal(request);
	//上述找不到則使用默認(rèn)的處理類,沒有設(shè)定則返回null,則會返回前臺404錯(cuò)誤
	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)先級:精確匹配>最長路徑匹配>擴(kuò)展名匹配
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		//HandlerMethod內(nèi)部含有bean對象,其實(shí)指的是對應(yīng)的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查找路徑對應(yīng)的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實(shí)現(xiàn)獲取handler。

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

  • AbstractHandlerMethodMapping當(dāng)bean被注入到容器后會執(zhí)行一系列的初始化過程,用于注解@Controller,@RequestMapping來定義controller。
//容器啟動時(shí)會運(yùn)行此方法,完成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);
   }
}
//整個(gè)controller類的解析過程
protected void detectHandlerMethods(Object handler) {
   //根據(jù)name找出bean的類型
   Class<?> handlerType = (handler instanceof String ?
         obtainApplicationContext().getType((String) handler) : handler.getClass());
   if (handlerType != null) {
      //獲取真實(shí)的controller,如果是代理類獲取父類
      Class<?> userType = ClassUtils.getUserClass(handlerType);
      //對真實(shí)的controller所有的方法進(jìn)行解析和處理  key為方法對象,T為注解封裝后的對象RequestMappingInfo
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> {
               try {
                  // 調(diào)用子類RequestMappingHandlerMapping的getMappingForMethod方法進(jìn)行處理,
                  // 即根據(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ìn)行處理,即根據(jù)RequestMapping注解信息創(chuàng)建匹配條件RequestMappingInfo對象getMappingForMethod(method, userType);
  3. 注冊處理方法registerHandlerMethod(handler, invocableMethod, mapping)
  • AbstractUrlHandlerMapping是AbstractHandlerMapping的子類,實(shí)現(xiàn)針對beanName注冊為handler對象。
//注冊url和Bean的map,將具體的Handler注入到url對應(yīng)的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.
   // 不是懶加載,默認(rèn)為false,即不是,通過配置SimpleUrlHandlerMapping屬性lazyInitHandlers的值進(jìn)行控制
   // 如果不是懶加載并且handler為單例,即從上下文中查詢實(shí)例處理,此時(shí)resolvedHandler為handler實(shí)例對象;
   // 如果是懶加載或者h(yuǎn)andler不是單例,即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));
         }
         //"/"-->設(shè)置為roothandler
         setRootHandler(resolvedHandler);
      }
      else if (urlPath.equals("/*")) {
         if (logger.isTraceEnabled()) {
            logger.trace("Default mapping to " + getHandlerDescription(handler));
         }
         //對"/*"的匹配設(shè)置默認(rèn)的handler
         setDefaultHandler(resolvedHandler);
      }
      else {
         //其余的路徑綁定關(guān)系則存入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);
      //驗(yàn)證RequestMappingInfo是否有對應(yīng)不同的method,有則拋出異常
      validateMethodMapping(handlerMethod, mapping);
      //RequestMappingInfo和handlerMethod綁定
      this.mappingLookup.put(mapping, handlerMethod);
      List<String> directUrls = getDirectUrls(mapping);//可以配置多個(gè)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", "默認(rèn)的映射處理器示例");
        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實(shí)現(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();
    }
    //建立當(dāng)前ApplicationContext中controller和url的對應(yīng)關(guān)系
    protected void detectHandlers() throws BeansException {
        // 獲取應(yīng)用上下文
        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);//設(shè)置根處理器,即請求/的時(shí)候
            }
            else if (urlPath.equals("/*")) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Default mapping to " + getHandlerDescription(handler));
                }
                setDefaultHandler(resolvedHandler);//默認(rèn)處理器
            }
            else {
                this.handlerMap.put(urlPath, resolvedHandler);//注冊進(jìn)map
                if (logger.isTraceEnabled()) {
                    logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
                }
            }
        }
    }

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

SimpleUrlHandlerMapping

間接實(shí)現(xiàn)了org.springframework.web.servlet.HandlerMapping接口,直接實(shí)現(xiàn)該接口的是org.springframework.web.servlet.handler.AbstractHandlerMapping抽象類,映射Url與請求handler bean。支持映射bean實(shí)例和映射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;
    }
    // 實(shí)例化本類實(shí)例入口
    @Override
    public void initApplicationContext() throws BeansException {
        // 調(diào)用父類AbstractHandlerMapping的initApplicationContext方法,只要完成攔截器的注冊
        super.initApplicationContext();
        // 處理url和bean name,具體注冊調(diào)用父類完成
        registerHandlers(this.urlMap);
    }
    // 注冊映射關(guān)系,及將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類主要接收用戶設(shè)定的url與handler的映射關(guān)系,其實(shí)際的工作都是交由其父類來完成的

  • AbstractHandlerMapping 在創(chuàng)建初始化SimpleUrlHandlerMapping類時(shí),調(diào)用其父類的initApplicationContext()方法,該方法完成攔截器的初始化
  • AbstractUrlHandlerMapping在創(chuàng)建初始化SimpleUrlHandlerMapping類時(shí),調(diào)用AbstractUrlHandlerMapping類的registerHandler(urlPath,handler)方法

總結(jié)

在這里插入圖片描述

到此這篇關(guān)于Spring中的HandlerMapping執(zhí)行流程詳解的文章就介紹到這了,更多相關(guān)HandlerMapping執(zhí)行流程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot項(xiàng)目刪除Bean或者不加載Bean的問題解決

    SpringBoot項(xiàng)目刪除Bean或者不加載Bean的問題解決

    文章介紹了在Spring Boot項(xiàng)目中如何使用@ComponentScan注解和自定義過濾器實(shí)現(xiàn)不加載某些Bean的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2025-01-01
  • 關(guān)于Java中的try-with-resources語句

    關(guān)于Java中的try-with-resources語句

    這篇文章主要介紹了關(guān)于Java中的try-with-resources語句,try-with-resources是Java中的環(huán)繞語句之一,旨在減輕開發(fā)人員釋放try塊中使用的資源的義務(wù),需要的朋友可以參考下
    2023-05-05
  • SpringMVC+MyBatis實(shí)現(xiàn)多數(shù)據(jù)源切換

    SpringMVC+MyBatis實(shí)現(xiàn)多數(shù)據(jù)源切換

    在企業(yè)級應(yīng)用開發(fā)中,經(jīng)常需要處理來自不同數(shù)據(jù)庫的數(shù)據(jù),為了滿足這一需求,我們可以通過配置多個(gè)數(shù)據(jù)源來實(shí)現(xiàn)對不同數(shù)據(jù)庫的訪問,下面我們來看看具體實(shí)現(xiàn)吧
    2025-01-01
  • SpringBoot中使用Quartz管理定時(shí)任務(wù)的方法

    SpringBoot中使用Quartz管理定時(shí)任務(wù)的方法

    這篇文章主要介紹了SpringBoot中使用Quartz管理定時(shí)任務(wù)的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • 如何解決SpringBoot定時(shí)任務(wù)報(bào)錯(cuò)Unexpected error occurred in scheduled task問題

    如何解決SpringBoot定時(shí)任務(wù)報(bào)錯(cuò)Unexpected error occurred 

    這篇文章主要介紹了如何解決SpringBoot定時(shí)任務(wù)報(bào)錯(cuò)Unexpected error occurred in scheduled task問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Spring Boot無縫集成MongoDB

    Spring Boot無縫集成MongoDB

    這篇文章主要介紹了Spring Boot無縫集成MongoDB的相關(guān)知識,本文涉及到MongoDB的概念和nosql的應(yīng)用場景,需要的朋友可以參考下
    2017-04-04
  • mybatis存在更新不存在新增問題

    mybatis存在更新不存在新增問題

    這篇文章主要介紹了mybatis存在更新不存在新增問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • springboot security之前后端分離配置方式

    springboot security之前后端分離配置方式

    這篇文章主要介紹了springboot security之前后端分離配置方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • Spring學(xué)習(xí)教程之AOP模塊的概述

    Spring學(xué)習(xí)教程之AOP模塊的概述

    AOP 從功能的角度來講,可能看作OOP編程方式的一種補(bǔ)充,提供了一種不同的代碼或者系統(tǒng)組織方式,下面這篇文章主要給大家介紹了關(guān)于Spring學(xué)習(xí)教程之AOP模塊的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2018-05-05
  • IDEA 快速返回上次查看代碼的位置的方法

    IDEA 快速返回上次查看代碼的位置的方法

    這篇文章主要介紹了IDEA 快速返回上次查看代碼的位置的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08

最新評論