zoukankan      html  css  js  c++  java
  • SPRING MVC源码解析

    DispatcherServlet extends FrameworkServlet extends HttpServletBean extends HttpServletBean extends HttpServlet

    服务方法 请求的第一个方法

    
    /**
    	 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
    	 * for the actual dispatching.
    	 */
    	@Override
    	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		if (logger.isDebugEnabled()) {
    			String requestUri = urlPathHelper.getRequestUri(request);
    			logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() +
    					" request for [" + requestUri + "]");
    		}
    
    		// Keep a snapshot of the request attributes in case of an include,
    		// to be able to restore the original attributes after the include.
    		Map<String, Object> attributesSnapshot = null;
    		if (WebUtils.isIncludeRequest(request)) {
    			logger.debug("Taking snapshot of request attributes before include");
    			attributesSnapshot = new HashMap<String, Object>();
    			Enumeration attrNames = request.getAttributeNames();
    			while (attrNames.hasMoreElements()) {
    				String attrName = (String) attrNames.nextElement();
    				if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
    					attributesSnapshot.put(attrName, request.getAttribute(attrName));
    				}
    			}
    		}
    
    		// Make framework objects available to handlers and view objects.
    		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
    		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
    
    		try {
    			[u][b]doDispatch(request, response);[/b][/u]		}
    		finally {
    			// Restore the original attribute snapshot, in case of an include.
    			if (attributesSnapshot != null) {
    				restoreAttributesAfterInclude(request, attributesSnapshot);
    			}
    		}
    	}
    
    



    Process the actual dispatching to the handler
    本次请求实际的请求方法
    
    	/**
    	 * Process the actual dispatching to the handler.
    	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
    	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
    	 * to find the first that supports the handler class.
    	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
    	 * themselves to decide which methods are acceptable.
    	 * @param request current HTTP request
    	 * @param response current HTTP response
    	 * @throws Exception in case of any kind of processing failure
    	 */
    	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		HttpServletRequest processedRequest = request;
    		HandlerExecutionChain mappedHandler = null;
    		int interceptorIndex = -1;
    
    		try {
    			ModelAndView mv;
    			boolean errorView = false;
    
    			try {
    				processedRequest = checkMultipart(request);
    
    				// Determine handler for the current request.
    				mappedHandler = getHandler(processedRequest, false);
    				if (mappedHandler == null || mappedHandler.getHandler() == null) {
    					noHandlerFound(processedRequest, response);
    					return;
    				}
    
    				// Determine handler adapter for the current request.
    				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                    // Process last-modified header, if supported by the handler.
    				String method = request.getMethod();
    				boolean isGet = "GET".equals(method);
    				if (isGet || "HEAD".equals(method)) {
    					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    					if (logger.isDebugEnabled()) {
    						String requestUri = urlPathHelper.getRequestUri(request);
    						logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
    					}
    //如果是get请求则判断是否有客户端缓存
    					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    						return;
    					}
    				}
    
    				// Apply preHandle methods of registered interceptors.
    				HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
    				if (interceptors != null) {
    					for (int i = 0; i < interceptors.length; i++) {
    						HandlerInterceptor interceptor = interceptors[i];
    						if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
    							triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
    							return;
    						}
    						interceptorIndex = i;
    					}
    				}
    //实际请求方法
    				// Actually invoke the handler.
    				mv =[b] ha.handle(processedRequest, response, mappedHandler.getHandler());[/b]
    				// Do we need view name translation?
    				if (mv != null && !mv.hasView()) {
    					mv.setViewName(getDefaultViewName(request));
    				}
    
    				// Apply postHandle methods of registered interceptors.
    				if (interceptors != null) {
    					for (int i = interceptors.length - 1; i >= 0; i--) {
    						HandlerInterceptor interceptor = interceptors[i];
    						interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
    					}
    				}
    			}
    			catch (ModelAndViewDefiningException ex) {
    				logger.debug("ModelAndViewDefiningException encountered", ex);
    				mv = ex.getModelAndView();
    			}
    			catch (Exception ex) {
    				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
    				mv = processHandlerException(processedRequest, response, handler, ex);
    				errorView = (mv != null);
    			}
    
    			// Did the handler return a view to render?
    			if (mv != null && !mv.wasCleared()) {
    				render(mv, processedRequest, response);
    				if (errorView) {
    					WebUtils.clearErrorRequestAttributes(request);
    				}
    			}
    			else {
    				if (logger.isDebugEnabled()) {
    					logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
    							"': assuming HandlerAdapter completed request handling");
    				}
    			}
    
    			// Trigger after-completion for successful outcome.
    			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
    		}
    
    		catch (Exception ex) {
    			// Trigger after-completion for thrown exception.
    			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
    			throw ex;
    		}
    		catch (Error err) {
    			ServletException ex = new NestedServletException("Handler processing failed", err);
    			// Trigger after-completion for thrown exception.
    			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
    			throw ex;
    		}
    
    		finally {
    			// Clean up any resources used by a multipart request.
    			if (processedRequest != request) {
    				cleanupMultipart(processedRequest);
    			}
    		}
    	}
    
    


    4个实现类



    //AnnotationMethodHandlerAdapter 注解实现类

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    
    		Class<?> clazz = ClassUtils.getUserClass(handler);
    		Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
    		if (annotatedWithSessionAttributes == null) {
    			annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
    			this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
    		}
    
    		if (annotatedWithSessionAttributes) {
    			// Always prevent caching in case of session attribute management.
    			checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
    			// Prepare cached set of session attributes names.
    		}
    		else {
    			// Uses configured default cacheSeconds setting.
    			checkAndPrepare(request, response, true);
    		}
    
    		// 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) {
    					return invokeHandlerMethod(request, response, handler);
    				}
    			}
    		}
    
    		[b]return invokeHandlerMethod(request, response, handler);[/b]	}
    
    
    
    
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    //handler方法解析器
    		ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
    //handler方法
    		Method handlerMethod = methodResolver.resolveHandlerMethod(request);
    //handler方法的执行器
    		ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
    
    		ServletWebRequest webRequest = new ServletWebRequest(request, response);
    //上下文map对象 request 及session中的Attribute
    		ExtendedModelMap implicitModel = new BindingAwareModelMap();
    //执行handler方法
    		Object [b]result [/b]= methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
    //将执行结果转化的为modelAndView对象
    		ModelAndView mav =
    				methodInvoker.getModelAndView(handlerMethod, handler.getClass(), [b]result[/b], implicitModel, webRequest);
    //将当前上下文的内容更新到modelView对象中
    		methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
    		return mav;
    	}
    
    


    执行handler 方法
    public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
    			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
    
    		Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
    		try {
    			boolean debug = logger.isDebugEnabled();
    //将ssesion中的内容加入到	implicitModel		
    for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
    				Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
    				if (attrValue != null) {
    					implicitModel.addAttribute(attrName, attrValue);
    				}
    			}
    /*先执行ModelAttributeMethods暴露表单引用对象为模型数据:放在处理器的一般方法(非功能处理方法)上时,是为表单准备要展示的表单引用对象,如注册时需要选择的所在城市等,而且在执行功能处理方法(@RequestMapping注解的方法)之前,自动添加到模型对象中,用于视图页面展示时使用
    
    /**
     * Annotation that binds a method parameter or method return value
     * to a named model attribute, exposed to a web view. Supported
     * for {@link RequestMapping} annotated handler classes.
     *
     * <p>Can be used to expose command objects to a web view, using
     * specific attribute names, through annotating corresponding
     * parameters of a {@link RequestMapping} annotated handler method).
     *
     * <p>Can also be used to expose reference data to a web view
     * through annotating accessor methods in a controller class which
     * is based on {@link RequestMapping} annotated handler methods,
     * with such accessor methods allowed to have any arguments that
     * {@link RequestMapping} supports for handler methods, returning
     * the model attribute value to expose.
     *
     * @author Juergen Hoeller
     * @since 2.5
     */
    @Target({ElementType.PARAMETER, ElementType.METHOD})
    //该注解可以注解在方法或参数上
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ModelAttribute {
    
    	/**
    	 * The name of the model attribute to bind to.
    	 * <p>The default model attribute name is inferred from the declared
    	 * attribute type (i.e. the method parameter type or method return type),
    	 * based on the non-qualified class name:
    	 * e.g. "orderAddress" for class "mypackage.OrderAddress",
    	 * or "orderAddressList" for "List&lt;mypackage.OrderAddress&gt;".
    	 */
    	String value() default "";
    
    }
    */
    
    
    //该注解在方法上
    
    			for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
    				Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
    				Object[] args = [b]resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);[/b]				if (debug) {
    					logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
    				}
    				String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
    				if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
    					continue;
    				}
    				ReflectionUtils.makeAccessible(attributeMethodToInvoke);
    				Object attrValue = attributeMethodToInvoke.invoke(handler, args);
    				if ("".equals(attrName)) {
    					Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
    					attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
    				}
    				if (!implicitModel.containsAttribute(attrName)) {
    					implicitModel.addAttribute(attrName, attrValue);
    				}
    			}
    			Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
    			if (debug) {
    				logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
    			}
    			ReflectionUtils.makeAccessible(handlerMethodToInvoke);
    //执行请求方法
    			return handlerMethodToInvoke.invoke(handler, args);
    		}
    		catch (IllegalStateException ex) {
    			// Internal assertion failed (e.g. invalid signature):
    			// throw exception with full handler method context...
    			throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
    		}
    		catch (InvocationTargetException ex) {
    			// User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
    			ReflectionUtils.rethrowException(ex.getTargetException());
    			return null;
    		}
    	}
    
    


    获取反射执行方法所需要的参数

    
    private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
    			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
    
    		Class[] paramTypes = handlerMethod.getParameterTypes();
    		Object[] args = new Object[paramTypes.length];
    
    		for (int i = 0; i < args.length; i++) {
    			MethodParameter methodParam = new MethodParameter(handlerMethod, i);
    			methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
    			GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
    			String paramName = null;
    			String headerName = null;
    			boolean requestBodyFound = false;
    			String cookieName = null;
    			String pathVarName = null;
    			String attrName = null;
    			boolean required = false;
    			String defaultValue = null;
    			boolean validate = false;
    			int annotationsFound = 0;
    			Annotation[] paramAnns = methodParam.getParameterAnnotations();
    
    			for (Annotation paramAnn : paramAnns) {
    				if (RequestParam.class.isInstance(paramAnn)) {
    					RequestParam requestParam = (RequestParam) paramAnn;
    					paramName = requestParam.value();
    					required = requestParam.required();
    					defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
    					annotationsFound++;
    				}
    				else if (RequestHeader.class.isInstance(paramAnn)) {
    					RequestHeader requestHeader = (RequestHeader) paramAnn;
    					headerName = requestHeader.value();
    					required = requestHeader.required();
    					defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
    					annotationsFound++;
    				}
    				else if (RequestBody.class.isInstance(paramAnn)) {
    					requestBodyFound = true;
    					annotationsFound++;
    				}
    				else if (CookieValue.class.isInstance(paramAnn)) {
    					CookieValue cookieValue = (CookieValue) paramAnn;
    					cookieName = cookieValue.value();
    					required = cookieValue.required();
    					defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
    					annotationsFound++;
    				}
    				else if (PathVariable.class.isInstance(paramAnn)) {
    					PathVariable pathVar = (PathVariable) paramAnn;
    					pathVarName = pathVar.value();
    					annotationsFound++;
    				}
    //这里是参数类型 该注解在参数上
    				else if (ModelAttribute.class.isInstance(paramAnn)) {
    					ModelAttribute attr = (ModelAttribute) paramAnn;
    					attrName = attr.value();
    					annotationsFound++;
    				}
    				else if (Value.class.isInstance(paramAnn)) {
    					defaultValue = ((Value) paramAnn).value();
    				}
    				else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) {
    					validate = true;
    				}
    			}
    
    			if (annotationsFound > 1) {
    				throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
    						"do not specify more than one such annotation on the same parameter: " + handlerMethod);
    			}
    
    			if (annotationsFound == 0) {
    				Object argValue = resolveCommonArgument(methodParam, webRequest);
    				if (argValue != WebArgumentResolver.UNRESOLVED) {
    					args[i] = argValue;
    				}
    				else if (defaultValue != null) {
    					args[i] = resolveDefaultValue(defaultValue);
    				}
    				else {
    					Class paramType = methodParam.getParameterType();
    					if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
    						args[i] = implicitModel;
    					}
    					else if (SessionStatus.class.isAssignableFrom(paramType)) {
    						args[i] = this.sessionStatus;
    					}
    					else if (HttpEntity.class.isAssignableFrom(paramType)) {
    						args[i] = resolveHttpEntityRequest(methodParam, webRequest);
    					}
    					else if (Errors.class.isAssignableFrom(paramType)) {
    						throw new IllegalStateException("Errors/BindingResult argument declared " +
    								"without preceding model attribute. Check your handler method signature!");
    					}
    					else if (BeanUtils.isSimpleProperty(paramType)) {
    						paramName = "";
    					}
    					else {
    						attrName = "";
    					}
    				}
    			}
    
    			if (paramName != null) {
    				args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
    			}
    			else if (headerName != null) {
    				args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
    			}
    			else if (requestBodyFound) {
    				args[i] = resolveRequestBody(methodParam, webRequest, handler);
    			}
    			else if (cookieName != null) {
    				args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
    			}
    			else if (pathVarName != null) {
    				args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
    			}
    //struts 2的模型驱动
    			else if (attrName != null) {
    				WebDataBinder binder =
    						resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
    				boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
    				if (binder.getTarget() != null) {
    					doBind(binder, webRequest, validate, !assignBindingResult);
    				}
    				args[i] = binder.getTarget();
    				if (assignBindingResult) {
    					args[i + 1] = binder.getBindingResult();
    					i++;
    				}
    				implicitModel.putAll(binder.getBindingResult().getModel());
    			}
    		}
    
    		return args;
    	}
    

    //模型注入
    private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,
    			ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {
    
    		// Bind request parameter onto object...
    		String name = attrName;
    		if ("".equals(name)) {
    			name = Conventions.getVariableNameForParameter(methodParam);
    		}
    		Class<?> paramType = methodParam.getParameterType();
    		Object bindObject;
    		if (implicitModel.containsKey(name)) {
    			bindObject = implicitModel.get(name);
    		}
    		else if (this.methodResolver.isSessionAttribute(name, paramType)) {
    			bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
    			if (bindObject == null) {
    				raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
    			}
    		}
    		else {
    			bindObject = BeanUtils.instantiateClass(paramType);
    		}
    		WebDataBinder binder = createBinder(webRequest, bindObject, name);
    		initBinder(handler, name, binder, webRequest);
    		return binder;
    	}
    
    
    	protected void initBinder(Object handler, String attrName, WebDataBinder binder, NativeWebRequest webRequest)
    			throws Exception {
    
    		if (this.bindingInitializer != null) {
    			this.bindingInitializer.initBinder(binder, webRequest);
    		}
    		if (handler != null) {
    			Set<Method> initBinderMethods = this.methodResolver.getInitBinderMethods();
    			if (!initBinderMethods.isEmpty()) {
    				boolean debug = logger.isDebugEnabled();
    				for (Method initBinderMethod : initBinderMethods) {
    					Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod);
    					String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value();
    					if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) {
    						Object[] initBinderArgs =
    								resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest);
    						if (debug) {
    							logger.debug("Invoking init-binder method: " + methodToInvoke);
    						}
    						ReflectionUtils.makeAccessible(methodToInvoke);
    						Object returnValue = methodToInvoke.invoke(handler, initBinderArgs);
    						if (returnValue != null) {
    							throw new IllegalStateException(
    									"InitBinder methods must not have a return value: " + methodToInvoke);
    						}
    					}
    				}
    			}
    		}
    	}
    
  • 相关阅读:
    C# 根据二级栏目Id查询出所属文章的信息列表
    C#网站首页制作MVC
    C#Mvc退出登录
    C#Mvc修改密码
    C#网站开发之内容页Content
    C#Mvc登录功能
    Linux命令——shell
    学习笔记cisco常用命令
    性能相关术语
    Linux命令(一)
  • 原文地址:https://www.cnblogs.com/hiaming/p/8967806.html
Copyright © 2011-2022 走看看