DispatcherServlet前端控制器结构分析

一、DispatcherServlet源码结构

DispatcherServlet前端控制器结构分析_第1张图片

二、DispatcherServlet类中doDispatch()方法

其中最重要的两个方法是ha.handle()执行目标方法,processDispatchResult()转发到页面

   protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
     
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
     
            try {
     
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
     
                	//1、checkMultipart(request)检查是否是文件上传请求
                    processedRequest = this.checkMultipart(request);
                    //如果是文件上传请求,那么request包装成了processedRequest,就不等于了原来的request请求,用变量multipartRequestParsed 记录了是否是文件上传请求
                    multipartRequestParsed = processedRequest != request;
                    //2、根据当前请求确定使用哪个处理器
                    mappedHandler = this.getHandler(processedRequest);
                    //3、如果没有找到哪个处理器能处理这个请求就404或者抛出异常
                    if (mappedHandler == null) {
     
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
					//4、拿到能执行这个处理器类的所有方法的适配器(反射工具)
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
     
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
     
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
     
                        return;
                    }
					//5、Controller处理器的方法被调用,通过前面拿到的ha适配器来执行相应的目标方法,并将目标方法返回值作为试图名,设置保存到ModelAndView中
					//目标无法无论返回什么,最终适配器执行完成以后都会将执行后的信息封装成ModelAndView返回
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
     
                        return;
                    }
					//如果目标方法返回值是void,那么就会设置一个默认的试图名
                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
     
                    dispatchException = var20;
                } catch (Throwable var21) {
     
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
                
				//6、转发到目标页面。根据方法最终执行完成封装的ModelAndView,转发到对应页面,而且ModelAndView中的数据可以从请求域中获取
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
     
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
     
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
     
            if (asyncManager.isConcurrentHandlingStarted()) {
     
                if (mappedHandler != null) {
     
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
     
                this.cleanupMultipart(processedRequest);
            }

        }
    }

请求的流程:

1、所有请求过来DispatcherServlet收到请求
2、调用doDispatch()方法处理请求

  • 调用getHandler()方法,根据当前请求地址找到能处理这个请求的目标处理器类(控制器)
    可以根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
  • 调用getHandlerAdapter()方法,根据当前处理器类获取到能执行这个处理器方法的适配器
    可以根据当前处理器类,找到当前类的HandlerAdapter(适配器)
  • 使用获取到的适配器(AnnotationMethodHandlerAdapter)执行目标方法
  • 目标方法执行后适配器将其返回值封装成一个ModelAndView对象并返回
  • 根据ModelAndView的信息转发到具体的页面,并可以在请求域中取出ModelAndView中模型数据

getHandler()方法

此方法根据当前请求能够找到哪个类可以处理该请求,方法会返回目标处理器类的执行链

IOC容器启动创建Controller对象的时候扫描每个处理器都能处理什么请求,保存在HandlerMappinghandlerMap属性中,等下一次请求过来的时候,就来看哪个HandlerMapping中有这个请求映射信息就可以了。

    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
     
        //handlerMapping:处理器映射,里面保存了每一个处理器能够处理哪些请求的映射信息
        if (this.handlerMappings != null) {
     
            Iterator var2 = this.handlerMappings.iterator();

            while(var2.hasNext()) {
     
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
     
                    return handler;
                }
            }
        }

        return null;
    }

getHandlerAdapter()方法

此方法可以找到目标处理器类的适配器,只有得到适配器才能执行目标方法。

   protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
     
        if (this.handlerAdapters != null) {
     
            Iterator var2 = this.handlerAdapters.iterator();

            while(var2.hasNext()) {
     
                HandlerAdapter adapter = (HandlerAdapter)var2.next();
                //判断循环中当前的适配器是否支持目标处理器类
                if (adapter.supports(handler)) {
     
                    return adapter;
                }
            }
        }

        throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

HttpRequestHandlerAdapter

	public boolean supports(Object handler) {
     
		//判断当前的处理器是否实现了HttpRequestHandler这个接口
		return (handler instanceof HttpRequestHandler);
	}

SimpleControllerHandlerAdapter

	@Override
	public boolean supports(Object handler) {
     
		//判断当前的处理器是否实现了Controller这个接口
		return (handler instanceof Controller);
	}

AbstractHandlerMethodAdapter

其中包含了可以解析注解方法的适配器,处理器类中只要标注了注解的这些方法就能用

	public final boolean supports(Object handler) {
     
		//
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}

ha.handle()方法

此方法用来确定目标方法并执行目标方法

mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 

执行目标方法后,返回ModelAndView

	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
     

		ModelAndView mav;
		checkRequest(request);

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {
     
			HttpSession session = request.getSession(false);
			if (session != null) {
     
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
     
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
     
				// No HttpSession available -> no mutex necessary
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
     
			// No synchronization on session demanded at all...
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
     
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
     
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
     
				prepareResponse(response);
			}
		}

		return mav;
	}

调用invokeHandlerMethod()方法

	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
     
		//将HttpServletRequest 包装成ServletWebRequest 
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
     
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			if (this.argumentResolvers != null) {
     
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			if (this.returnValueHandlers != null) {
     
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);

			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			asyncManager.setTaskExecutor(this.taskExecutor);
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			asyncManager.registerCallableInterceptors(this.callableInterceptors);
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

			if (asyncManager.hasConcurrentResult()) {
     
				Object result = asyncManager.getConcurrentResult();
				mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
				asyncManager.clearConcurrentResult();
				LogFormatUtils.traceDebug(logger, traceOn -> {
     
					String formatted = LogFormatUtils.formatValue(result, !traceOn);
					return "Resume with async result [" + formatted + "]";
				});
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}

			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
     
				return null;
			}

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
     
			webRequest.requestCompleted();
		}
	}

真正执行目标方法的代码,目标方法利用反射执行期间确定参数值,提前执行modelAttribute等所有的操作都在这个方法中。

invocableMethod.invokeAndHandle(webRequest, mavContainer);

确定目标方法的每个参数的值

    protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
     
        MethodParameter[] parameters = this.getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
     
            return EMPTY_ARGS;
        } else {
     
        	//创建和参数长度一样长的数组
            Object[] args = new Object[parameters.length];
			//通过循环得到每一个参数的信息
            for(int i = 0; i < parameters.length; ++i) {
     
                MethodParameter parameter = parameters[i];
                parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
                args[i] = findProvidedArgument(parameter, providedArgs);
                if (args[i] == null) {
     
                    if (!this.resolvers.supportsParameter(parameter)) {
     
                        throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
                    }

                    try {
     
                        args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                    } catch (Exception var10) {
     
                        if (this.logger.isDebugEnabled()) {
     
                            String exMsg = var10.getMessage();
                            if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
     
                                this.logger.debug(formatArgumentError(parameter, exMsg));
                            }
                        }

                        throw var10;
                    }
                }
            }

            return args;
        }
    }

对于有注解的参数,保存参数是哪个注解的详细信息,如果参数有ModelAttribute注解,就会拿到这个注解的值让attrName保存。

对于没有注解的参数,首先看是否是普通参数(即是否是原生API);再看是否是Model或者Map;如果是就传入隐含模型保存。如果不是普通参数而是自定义类型的参数,如果没ModelAttribute注解,就会先看是否是原生API;再看是否是Model或者Map;再看是否是其它类型,如SessionStatusHttpEntityErrors类型;都不是最后再看是否是简单类型属性,如IntegerString等,会给paramName赋值。如果所有类型都不是则attrName=""。如果是自定义类型的对象,最终会产生两个效果,即如果这个参数标注了ModelAttribute注解就会给attrName赋值为这个注解的value值;如果这个参数没有标注ModelAttribute注解就会给attName赋值为""

确定POJO值

SpringMVC确定POJO的值分为三步:

  • 如果隐含模型中有这个key(即标了ModelAttribute注解),则POJO就是注解指定的value,没有标注解就是参数类型的首字母小写指定的值。如果有将这个值赋值给bindObject
  • 如果有SessionAttributes标注的属性,就会从Session中取值。
  • 如果都不是就会利用反射创建对象。

DispatcherServlet前端控制器结构分析_第2张图片

三、SpringMVC九大组件

DispatcherServlet类中有九个引用类型的属性,称为SpringMVC九大组件,SpringMVC在工作的时候,关键位置都是由这些组件来完成的。

九大组件都是接口,接口就是规范,提供了非常强大的扩展性。SpringMVC核心就是九大组件的工作原理。

	/** MultipartResolver used by this servlet. */
	@Nullable
	private MultipartResolver multipartResolver;		//文件上传解析器

	/** LocaleResolver used by this servlet. */
	@Nullable
	private LocaleResolver localeResolver;				//区域信息解析器,和国际化有关

	/** ThemeResolver used by this servlet. */
	@Nullable
	private ThemeResolver themeResolver;				//主题解析器,强大的主题效果更换

	/** List of HandlerMappings used by this servlet. */
	@Nullable
	private List<HandlerMapping> handlerMappings;				//Handler映射信息

	/** List of HandlerAdapters used by this servlet. */	
	@Nullable
	private List<HandlerAdapter> handlerAdapters;				//Handler的适配器

	/** List of HandlerExceptionResolvers used by this servlet. */
	@Nullable
	private List<HandlerExceptionResolver> handlerExceptionResolvers;	//SpringMVC异常解析器

	/** RequestToViewNameTranslator used by this servlet. */
	@Nullable
	private RequestToViewNameTranslator viewNameTranslator;				//目标方法没有返回值,则把请求地址作为试图名,试图名转换器

	/** FlashMapManager used by this servlet. */
	@Nullable
	private FlashMapManager flashMapManager;							//FlashMap管理器,管理SpringMVC中运行重定向携带数据

	/** List of ViewResolvers used by this servlet. */
	@Nullable
	private List<ViewResolver> viewResolvers;							//试图解析器

九大组件初始化

服务器一启动就执行初始化方法

	protected void onRefresh(ApplicationContext context) {
     
		initStrategies(context);
	}

分别调用各个组件的初始化方法

	protected void initStrategies(ApplicationContext context) {
     
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

HandlerMapping初始化

	/**
	 * Initialize the HandlerMappings used by this class.
	 * 

If no HandlerMapping beans are defined in the BeanFactory for this namespace, * we default to BeanNameUrlHandlerMapping. */ private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. 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"); } } }

组件的初始化是去容器中找这个组件,如果没有找到就使用默认的配置,有些组件在容器中是使用类型找的,有些组件是使用id找的。

你可能感兴趣的:(SpringMVC,SpringMVC,前端控制器)