@@ -370,14 +370,398 @@ HandlerMappings完成对MVC中Controller的定义和配置,只不过在Web这
370370
371371## 4 SpringMVC 处理分发HTTP 请求
372372### 4.1 HandlerMapping 的配置和设计原理
373+ 前面分析了DispatcherServlet 对Spring MVC 框架的初始化过程,在此基础上,我们再进一步分析HandlerMapping 的实现原理,看看这个MVC 框架中比较关键的控制部分是如何实现的。
373374
375+ 在初始化完成时,在上下文环境中已定义的所有HandlerMapping 都已经被加载了,这些加载的handlerMappings被放在一个List 中并被排序,存储着HTTP 请求对应的映射数据。这个List 中的每一个元素都对应着一个具体handlerMapping的配置,一般每一个handlerMapping
376+ 可以持有一系列从URL 请求到Controller 的映射,而Spring MVC 提供了一系列的HandlerMapping 实现。
374377
378+ ! [avatar](/images/springMVC/HandlerMapping组件.png)
375379
376- ### 4.2 使用HandlerMapping 完成请求的映射处理
380+ 以SimpleUrlHandlerMapping这个handlerMapping为例来分析HandlerMapping的设计与实现。在SimpleUrlHandlerMapping中,定义了一个map来 持有 一系列的映射关系。通过这些在HandlerMapping中定义的映射关系,即这些URL请求和控制器的对应关系,使Spring MVC
381+ 应用可以根据HTTP请求确定一个对应的Controller。具体来说,这些映射关系是通过接口HandlerMapping来封装的,在HandlerMapping接 口中定义了一个getHandler方法,通过这个方法,可以获得与HTTP请求对应的HandlerExecutionChain,在这个HandlerExecutionChain
382+ 中,封装了具体的Controller对象。
383+ ```java
384+ public interface HandlerMapping {
385+
386+ String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping . class. getName() + " .pathWithinHandlerMapping" ;
387+
388+ String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping . class. getName() + " .bestMatchingPattern" ;
389+
390+ String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping . class. getName() + " .introspectTypeLevelMapping" ;
391+
392+ String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping . class. getName() + " .uriTemplateVariables" ;
393+
394+ String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping . class. getName() + " .matrixVariables" ;
395+
396+ String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping . class. getName() + " .producibleMediaTypes" ;
397+
398+ /**
399+ * 返回的这个HandlerExecutionChain不但持有handler本身,还包括了处理这个HTTP请求的拦截器
400+ */
401+ HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception ;
402+
403+ }
404+ ```
405+ 这个HandlerExecutionChain 的实现看起来比较简洁,它持有一个Interceptor 链和一个handler对象,这个handler对象实际上就是HTTP 请求对应的Controller ,在持有这个handler对象的同时,还在HandlerExecutionChain 中设置了一个拦截器链,通过这个拦截器链中的拦截器,
406+ 可以为handler对象提供功能的增强。要完成这些工作,需要对拦截器链和handler都进行配置,这些配置都是在HandlerExecutionChain 的初始化函数中完成的。为了维护这个拦截器链和handler,HandlerExecutionChain 还提供了一系列与拦截器链维护相关的操作,比如,为拦
407+ 截器链增加拦截器的addInterceptor ()方法。
408+ ```java
409+ public class HandlerExecutionChain {
410+
411+ private static final Log logger = LogFactory . getLog(HandlerExecutionChain . class);
412+
413+ private final Object handler;
414+
415+ private HandlerInterceptor [] interceptors;
416+
417+ private List<HandlerInterceptor > interceptorList;
418+
419+ private int interceptorIndex = - 1 ;
420+
421+
422+ public HandlerExecutionChain(Object handler) {
423+ this (handler, null );
424+ }
425+
426+ public HandlerExecutionChain(Object handler, HandlerInterceptor [] interceptors) {
427+ if (handler instanceof HandlerExecutionChain ) {
428+ HandlerExecutionChain originalChain = (HandlerExecutionChain ) handler;
429+ this . handler = originalChain. getHandler();
430+ this . interceptorList = new ArrayList<HandlerInterceptor > ();
431+ CollectionUtils . mergeArrayIntoCollection(originalChain. getInterceptors(), this . interceptorList);
432+ CollectionUtils . mergeArrayIntoCollection(interceptors, this . interceptorList);
433+ }
434+ else {
435+ this . handler = handler;
436+ this . interceptors = interceptors;
437+ }
438+ }
439+
440+ public Object getHandler() {
441+ return this . handler;
442+ }
443+
444+ /**
445+ * 为拦截器链 添加拦截器
446+ */
447+ public void addInterceptor(HandlerInterceptor interceptor) {
448+ initInterceptorList();
449+ this . interceptorList. add(interceptor);
450+ }
451+
452+ /**
453+ * 批量添加拦截器
454+ */
455+ public void addInterceptors(HandlerInterceptor [] interceptors) {
456+ if (interceptors != null ) {
457+ initInterceptorList();
458+ this . interceptorList. addAll(Arrays . asList(interceptors));
459+ }
460+ }
461+
462+ /**
463+ * 延迟初始化interceptorList和interceptors集合
464+ */
465+ private void initInterceptorList() {
466+ if (this . interceptorList == null ) {
467+ this . interceptorList = new ArrayList<HandlerInterceptor > ();
468+ }
469+ if (this . interceptors != null ) {
470+ this . interceptorList. addAll(Arrays . asList(this . interceptors));
471+ this . interceptors = null ;
472+ }
473+ }
474+
475+ public HandlerInterceptor [] getInterceptors() {
476+ if (this . interceptors == null && this . interceptorList != null ) {
477+ this . interceptors = this . interceptorList. toArray(new HandlerInterceptor [this . interceptorList. size()]);
478+ }
479+ return this . interceptors;
480+ }
481+
482+ @Override
483+ public String toString() {
484+ if (this . handler == null ) {
485+ return " HandlerExecutionChain with no handler" ;
486+ }
487+ StringBuilder sb = new StringBuilder ();
488+ sb. append(" HandlerExecutionChain with handler [" ). append(this . handler). append(" ]" );
489+ if (! CollectionUtils . isEmpty(this . interceptorList)) {
490+ sb. append(" and " ). append(this . interceptorList. size()). append(" interceptor" );
491+ if (this . interceptorList. size() > 1 ) {
492+ sb. append(" s" );
493+ }
494+ }
495+ return sb. toString();
496+ }
497+ }
498+ ```
499+ HandlerExecutionChain中定义的Handler和Interceptor需要在定义HandlerMapping时配置好,例如对具体的SimpleURLHandlerMapping,要做的就是根据URL映射的方式,注册Handler和Interceptor,从而维护一个反映这种映射关系的handlerMap。当需要匹配HTTP请求时,需要查询这个handlerMap中的信息来得到对应的HandlerExecutionChain。这些信息是什么时候配置好的呢?这里有一个注册过程,这个注册过程在容器对Bean进行依赖注入时发生,它实际上是通过一个Bean的postProcessor ()来完成的。以SimpleHandlerMapping为例,需要注意的是,这里用到了对容器的回调,只有SimpleHandlerMapping是ApplicationContextAware的子类才能启动这个注册过程。这个注册过程完成的是反映URL和Controller之间映射关系的handlerMap的建立。
500+
501+ 
502+
503+ ```java
504+ public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
505+ @Override
506+ public void initApplicationContext() throws BeansException {
507+ super . initApplicationContext();
508+ registerHandlers(this . urlMap);
509+ }
510+
511+ /**
512+ * 为相应的路径注册URL映射中指定的所有handlers处理程序
513+ */
514+ protected void registerHandlers(Map<String , Object > urlMap) throws BeansException {
515+ if (urlMap. isEmpty()) {
516+ logger. warn(" Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping" );
517+ }
518+ else {
519+ // 这里对bean的配置进行解析,然后调用父类的registerHandler()方法进行解析
520+ for (Map . Entry<String , Object > entry : urlMap. entrySet()) {
521+ String url = entry. getKey();
522+ Object handler = entry. getValue();
523+ // 如果url没有斜线,就在前面加上斜线
524+ if (! url. startsWith(" /" )) {
525+ url = " /" + url;
526+ }
527+ // Remove whitespace from handler bean name.
528+ if (handler instanceof String ) {
529+ handler = ((String ) handler). trim();
530+ }
531+ // 这里调用的是父类的方法
532+ registerHandler(url, handler);
533+ }
534+ }
535+ }
536+ }
537+ ```
538+ 这个SimpleUrlHandlerMapping 注册过程的完成,很大一部分需要它的基类来配合,这个基类就是AbstractUrlHandlerMapping 。在AbstractUrlHandlerMapping 的处理过程中,如果使用Bean 的名称作为映射,那么直接从容器中获取这个HTTP 映射对应的Bean ,然后还要对不同的URL 配置进行解析处理,比如在HTTP 请求中配置成“/ ”和通配符“/* ” 的URL,以及正常的URL请求,完成这个解析处理过程以后,会
539+ 把URL和handler作为键值对放到一个handlerMap中去。
540+ ```java
541+ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
542+ /**
543+ * 为给定的URL路径注册指定的handler处理程序
544+ */
545+ protected void registerHandler (String [] urlPaths , String beanName ) throws BeansException , IllegalStateException {
546+ Assert . notNull(urlPaths, " URL path array must not be null" );
547+ for (String urlPath : urlPaths) {
548+ registerHandler(urlPath, beanName);
549+ }
550+ }
551+
552+ /**
553+ * 为给定的URL路径注册指定的handler处理程序
554+ */
555+ protected void registerHandler (String urlPath , Object handler ) throws BeansException , IllegalStateException {
556+ Assert . notNull(urlPath, " URL path must not be null" );
557+ Assert . notNull(handler, " Handler object must not be null" );
558+ Object resolvedHandler = handler;
559+
560+ // 如果使用bean名称进行映射,就直接从IoC容器中获取该bean名称对应的handler
561+ if (! this . lazyInitHandlers && handler instanceof String ) {
562+ String handlerName = (String ) handler;
563+ if (getApplicationContext(). isSingleton(handlerName)) {
564+ resolvedHandler = getApplicationContext(). getBean(handlerName);
565+ }
566+ }
567+
568+ Object mappedHandler = this . handlerMap. get(urlPath);
569+ if (mappedHandler != null ) {
570+ if (mappedHandler != resolvedHandler) {
571+ throw new IllegalStateException (
572+ " Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
573+ " ]: There is already " + getHandlerDescription(mappedHandler) + " mapped." );
574+ }
575+ }
576+ else {
577+ // 处理URL是"/"的映射,把这个"/"映射的controller设置到rootHandler中
578+ if (urlPath. equals(" /" )) {
579+ if (logger. isInfoEnabled()) {
580+ logger. info(" Root mapping to " + getHandlerDescription(handler));
581+ }
582+ setRootHandler(resolvedHandler);
583+ }
584+ // 处理URL是"/"的映射,把这个"/"映射的controller设置到defaultHandler中
585+ else if (urlPath. equals(" /*" )) {
586+ if (logger. isInfoEnabled()) {
587+ logger. info(" Default mapping to " + getHandlerDescription(handler));
588+ }
589+ setDefaultHandler(resolvedHandler);
590+ }
591+ // 处理正常的URL映射,此handlerMap的key和value分别代表URL和映射的Controller
592+ else {
593+ this . handlerMap. put(urlPath, resolvedHandler);
594+ if (logger. isInfoEnabled()) {
595+ logger. info(" Mapped URL path [" + urlPath + " ] onto " + getHandlerDescription(handler));
596+ }
597+ }
598+ }
599+ }
600+
601+ /**
602+ * 为此handler映射设置根handler,即要为根路径("/")注册的handler
603+ * <p >Default is {@code null }, indicating no root handler.
604+ */
605+ public void setRootHandler (Object rootHandler ) {
606+ this . rootHandler = rootHandler;
607+ }
377608
609+ public Object getRootHandler () {
610+ return this . rootHandler;
611+ }
612+
613+ /**
614+ * 设置此handler映射的默认handler。如果未找到特定映射,则将返回此handler
615+ */
616+ public void setDefaultHandler (Object defaultHandler ) {
617+ this . defaultHandler = defaultHandler;
618+ }
619+
620+ public Object getDefaultHandler () {
621+ return this . defaultHandler;
622+ }
623+ }
624+ ```
625+ 这里的handlerMap是一个HashMap,其中保存了URL请求和Controller的映射关系,这个handlerMap是在AbstractUrlHandlerMapping中定义的( Map<String, object> handlerMap = new LinkedHashMap<String, object>() ),这个配置好URL请求和handler映射数据的handlerMap,为Spring MVC响应HTTP请求准备好了基本的映射数据,根据这个handlerMap以及设置于其中的映射数据,可以方便地由
626+ URL请求得到它所对应的handler。有了这些准备工作,Spring MVC就可以等待HTTP请求的到来了。
627+
628+ ### 4.2 使用HandlerMapping完成请求的映射处理
629+ 继续通过SimpleUrlHandlerMapping的实现来分析HandlerMapping的接口方法getHandler(),该方法会根据初始化时得到的映射关系来生成DispatcherServlet需要的HandlerExecutionChain,也就是说,这个getHandler()方法是实际使用HandlerMapping完成请求的映射处理的地方。在前面的HandlerExecutionChain的执行过程中,首先在AbstractHandlerMapping中启动getHandler的调用。
630+ ``` java
631+ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping , Ordered {
632+ /**
633+ * 查找给定请求的handler,如果找不到特定的handler,则返回到defaultHandler
634+ */
635+ public final HandlerExecutionChain getHandler (HttpServletRequest request ) throws Exception {
636+ // 模板方法模式
637+ Object handler = getHandlerInternal(request);
638+ // 如果找不到特定的handler,则取defaultHandler
639+ if (handler == null ) {
640+ handler = getDefaultHandler();
641+ }
642+ // defaultHandler也没有则返回null
643+ if (handler == null ) {
644+ return null ;
645+ }
646+ // 如果该handler是String类型的,说明它是一个beanname
647+ // 根据该beanname从IoC容器中获取真正的handler对象
648+ if (handler instanceof String ) {
649+ String handlerName = (String ) handler;
650+ handler = getApplicationContext(). getBean(handlerName);
651+ }
652+ // 这里把handler添加到到HandlerExecutionChain中
653+ return getHandlerExecutionChain(handler, request);
654+ }
655+ }
656+ ```
657+ 取得handler的具体过程在getHandlerInternal()方法中实现,这个方法接受HTTP请求作为参数,它的实现在AbstractHandlerMapping的子类AbstractUrlHandlerMapping中,这个实现过程包括从HTTP请求中得到URL,并根据URL到urlMapping中获得handler。
658+ ``` java
659+ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
660+ /**
661+ * 查找给定请求的URL路径 对应的handler
662+ */
663+ @Override
664+ protected Object getHandlerInternal (HttpServletRequest request ) throws Exception {
665+ // 从request中获取请求的URL路径
666+ String lookupPath = getUrlPathHelper(). getLookupPathForRequest(request);
667+ // 将得到的URL路径与handler进行匹配,得到对应的handler,如果没有对应的handler
668+ // 则返回null,这样默认的handler会被使用
669+ Object handler = lookupHandler(lookupPath, request);
670+ if (handler == null ) {
671+ // We need to care for the default handler directly, since we need to
672+ // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
673+ Object rawHandler = null ;
674+ if (" /" . equals(lookupPath)) {
675+ rawHandler = getRootHandler();
676+ }
677+ // 使用默认的handler
678+ if (rawHandler == null ) {
679+ rawHandler = getDefaultHandler();
680+ }
681+ if (rawHandler != null ) {
682+ // Bean name or resolved handler?
683+ if (rawHandler instanceof String ) {
684+ String handlerName = (String ) rawHandler;
685+ rawHandler = getApplicationContext(). getBean(handlerName);
686+ }
687+ validateHandler(rawHandler, request);
688+ handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null );
689+ }
690+ }
691+ if (handler != null && logger. isDebugEnabled()) {
692+ logger. debug(" Mapping [" + lookupPath + " ] to " + handler);
693+ }
694+ else if (handler == null && logger. isTraceEnabled()) {
695+ logger. trace(" No handler mapping found for [" + lookupPath + " ]" );
696+ }
697+ return handler;
698+ }
378699
700+ /**
701+ * 查找给定URL路径的handler实例
702+ */
703+ protected Object lookupHandler (String urlPath , HttpServletRequest request ) throws Exception {
704+ // 直接匹配
705+ Object handler = this . handlerMap. get(urlPath);
706+ if (handler != null ) {
707+ // Bean name or resolved handler?
708+ if (handler instanceof String ) {
709+ String handlerName = (String ) handler;
710+ handler = getApplicationContext(). getBean(handlerName);
711+ }
712+ validateHandler(handler, request);
713+ return buildPathExposingHandler(handler, urlPath, urlPath, null );
714+ }
715+ // 正则匹配
716+ List<String > matchingPatterns = new ArrayList<String > ();
717+ for (String registeredPattern : this . handlerMap. keySet()) {
718+ if (getPathMatcher(). match(registeredPattern, urlPath)) {
719+ matchingPatterns. add(registeredPattern);
720+ }
721+ }
722+ String bestPatternMatch = null ;
723+ Comparator<String > patternComparator = getPathMatcher(). getPatternComparator(urlPath);
724+ if (! matchingPatterns. isEmpty()) {
725+ Collections . sort(matchingPatterns, patternComparator);
726+ if (logger. isDebugEnabled()) {
727+ logger. debug(" Matching patterns for request [" + urlPath + " ] are " + matchingPatterns);
728+ }
729+ bestPatternMatch = matchingPatterns. get(0 );
730+ }
731+ if (bestPatternMatch != null ) {
732+ handler = this . handlerMap. get(bestPatternMatch);
733+ // Bean name or resolved handler?
734+ if (handler instanceof String ) {
735+ String handlerName = (String ) handler;
736+ handler = getApplicationContext(). getBean(handlerName);
737+ }
738+ validateHandler(handler, request);
739+ String pathWithinMapping = getPathMatcher(). extractPathWithinPattern(bestPatternMatch, urlPath);
740+
741+ // There might be multiple 'best patterns', let's make sure we have the correct URI template variables
742+ // for all of them
743+ Map<String , String > uriTemplateVariables = new LinkedHashMap<String , String > ();
744+ for (String matchingPattern : matchingPatterns) {
745+ if (patternComparator. compare(bestPatternMatch, matchingPattern) == 0 ) {
746+ Map<String , String > vars = getPathMatcher(). extractUriTemplateVariables(matchingPattern, urlPath);
747+ Map<String , String > decodedVars = getUrlPathHelper(). decodePathVariables(request, vars);
748+ uriTemplateVariables. putAll(decodedVars);
749+ }
750+ }
751+ if (logger. isDebugEnabled()) {
752+ logger. debug(" URI Template variables for request [" + urlPath + " ] are " + uriTemplateVariables);
753+ }
754+ return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
755+ }
756+ // No handler found...
757+ return null ;
758+ }
759+ }
760+ ```
761+ 经过这一系列对HTTP请求进行解析和匹配handler的过程,得到了与请求对应的handler处理器。在返回的handler中,已经完成了在HandlerExecutionChain中进行封装的工作,为handler对HTTP请求的响应做好了准备。
379762
380763### 4.3 DispatcherServlet对HTTP请求的分发处理
381764
382765
383766
767+
0 commit comments