spring-mvc-執行流程

不要問我閱讀spring源碼有什麼用,問就是沒有用,只是讓我本身使用spring的過程當中自信點!java

相關文章

spring-相關文章web

相關連接

  1. spring-mvc-handlerMapping 是怎麼存放咱們的請求路徑的-源碼
  2. springmvc-執行流程
  3. spring-mvc 時如何選擇 messageConverter
  4. springMVC-Interceptor-源碼分析

說明如下幾點:

  1. 本文針對的是普通的請求(處理@Controller).
  2. spring-mvc 的執行流程很簡單,主要就是經過java反射執行方法
  3. 執行目標爲handlerMethod(假如不懂請看juejin.im/post/5ddf84…)
  4. 雖然執行流程很簡單,可是也很難,難在對請求參數的處理.
  5. 內容會不少

開始

直接上代碼了spring

org.springframework.web.servlet.DispatcherServlet.doDispatch()json

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

	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

		try {
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);

			// Determine handler for the current request.
			//獲取執行鏈
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == 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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}
            //執行 攔截器
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// Actually invoke the handler.
			// 今天的重點,處理請求 進入這個方法
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}

			applyDefaultViewName(processedRequest, mv);
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}

	......................................
}

@Override
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;
}

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	.......................................
        // 這裏 進入主線
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}

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


public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    // 這裏 是主線 返回了 響應結果 進入方法
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	setResponseStatus(webRequest);

	if (returnValue == null) {
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
			mavContainer.setRequestHandled(true);
			return;
		}
	}
	else if (StringUtils.hasText(getResponseStatusReason())) {
		mavContainer.setRequestHandled(true);
		return;
	}

	mavContainer.setRequestHandled(false);
	Assert.state(this.returnValueHandlers != null, "No return value handlers");
	try {
	    //處理響應結果 例如返回的是json 仍是 xml,今天不說,下篇文章會說,也很重要
		this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	catch (Exception ex) {
		if (logger.isTraceEnabled()) {
			logger.trace(formatErrorForReturnValue(returnValue), ex);
		}
		throw ex;
	}
}

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    // 這篇文 最重要的地方,沒有之一 獲取請求參數
	Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
	if (logger.isTraceEnabled()) {
		logger.trace("Arguments: " + Arrays.toString(args));
	}
	//繼續執行流程 從名字大概也能夠猜到
	return doInvoke(args);
}

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

	if (ObjectUtils.isEmpty(getMethodParameters())) {
		return EMPTY_ARGS;
	}
	//MethodParameter 描述的 是 方法參數 : 包含 Method classType 參數下標
	//下面的代碼都是圍繞這 MethodParameter進行的 因此咱們稍微的去看看 MethodParameter 在哪裏註冊的.
	//是在 註冊 handlerMethod 的時候 被賦值的 因此咱們應該是從 requestMappingHandlerMapping 的afterPropertiesSet //開始看,可是咱們上篇已經講過了一部分的 requestMappingHandlerMapping 因此不細說了.
	MethodParameter[] parameters = getMethodParameters();
	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) {
			continue;
		}
		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 ex) {
			// Leave stack trace for later, exception may actually be resolved and handled..
			if (logger.isDebugEnabled()) {
				String error = ex.getMessage();
				if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
					logger.debug(formatArgumentError(parameter, error));
				}
			}
			throw ex;
		}
	}
	return args;
}
複製代碼

parameters 是如何被加載的

//從這行代碼能夠看到 值就是 methodhandler 的 parameters屬性
public MethodParameter[] getMethodParameters() {
	return this.parameters;
}
//直接到 建立methodHandler 的地方
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
	HandlerMethod handlerMethod;
	if (handler instanceof String) {
		String beanName = (String) handler;
		//new 了 一個 methodHandler
		handlerMethod = new HandlerMethod(beanName,
				obtainApplicationContext().getAutowireCapableBeanFactory(), method);
	}
	else {
		handlerMethod = new HandlerMethod(handler, method);
	}
	return handlerMethod;
}
//HandlerMethod 的構造方法
public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
    //這一些賦值不說了,一目瞭然
	Assert.hasText(beanName, "Bean name is required");
	Assert.notNull(beanFactory, "BeanFactory is required");
	Assert.notNull(method, "Method is required");
	this.bean = beanName;
	this.beanFactory = beanFactory;
	Class<?> beanType = beanFactory.getType(beanName);
	if (beanType == null) {
		throw new IllegalStateException("Cannot resolve bean type for bean with name '" + beanName + "'");
	}
	this.beanType = ClassUtils.getUserClass(beanType);
	this.method = method;
	//這個地方其實就是把 Method 賦值給 bridgedMethod 
	this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
	//在這個地方 給 parameters 賦值
	this.parameters = initMethodParameters();
	evaluateResponseStatus();
}
//建立MethodParameter 
private MethodParameter [] initMethodParameters() {
    //上面說過了 bridgedMethod 就是 method,說明方法存在幾個參數,parameters 的長度就是多少
	int count = this.bridgedMethod.getParameterCount();
	MethodParameter[] result = new MethodParameter[count];
	for (int i = 0; i < count; i++) {
	    //調用 HandlerMethodParameter的構造方法,i 這個參數是下標,別幹別的事,裏面不看了
		HandlerMethodParameter parameter = new HandlerMethodParameter(i);
		//修改 建立的HandlerMethodParameter 裏面也就是對parmeter 一系列的賦值
		GenericTypeResolver.resolveParameterType(parameter, this.beanType);
		result[i] = parameter;
	}
	//結束
	//可是,注意,這個HandlerMethodParameter 裏面 存在 描述 參數名 的屬性,可是如今並無值.
	return result;
}

複製代碼

上面看了 parameters是如何被賦值的,如今接着看

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

	if (ObjectUtils.isEmpty(getMethodParameters())) {
		return EMPTY_ARGS;
	}
	//剛剛看到了這裏,如今接着看
	MethodParameter[] parameters = getMethodParameters();
	//建立一個空的 定長的數組,用來存放請求參數
	Object[] args = new Object[parameters.length];
	for (int i = 0; i < parameters.length; i++) {
	    //獲取 MethodParameter
		MethodParameter parameter = parameters[i];
		
		//賦值操做,是個處理器
		parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
		args[i] = findProvidedArgument(parameter, providedArgs);
		if (args[i] != null) {
			continue;
		}
		//這裏挺重要的,這裏的做用是判斷是否存在能處理當前參數的解析器,假如存在就放入緩存(map)
		//key 爲 parameter value 爲 resolvers 裏面調用了 getArgumentResolver 下面代碼還會再次調用
		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 ex) {
			// Leave stack trace for later, exception may actually be resolved and handled..
			if (logger.isDebugEnabled()) {
				String error = ex.getMessage();
				if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
					logger.debug(formatArgumentError(parameter, error));
				}
			}
			throw ex;
		}
	}
	return args;
}
//獲取解析器,並執行
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

    //上面說過這個方法還會再次調用,獲取解析器 
    /** *這個方法比較重要,不一樣的參數不一樣的解析器,比較多,可是不進去看了,咱們只說,兩種狀況,1參數爲實體類的狀況,2參數爲基本類型和String *1 的 處理器 爲: ServletModelAttributeMethodProcessor(獲取的) *ModelAttributeMethodProcessor(實際執行的,父子關係) *2 的 處理器 爲:RequestParamMethodArgumentResolver(獲取的) AbstractNamedValueMethodArgumentResolver(實際執行的,父子關係) */
	HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
	if (resolver == null) {
		throw new IllegalArgumentException(
				"Unsupported parameter type [" + parameter.getParameterType().getName() + "]." +
						" supportsParameter should be called first.");
	}
	//執行
	return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

複製代碼

AbstractNamedValueMethodArgumentResolver

public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    //這個方法重點看下 主要就是建立 NamedValueInfo
	NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
	MethodParameter nestedParameter = parameter.nestedIfOptional();

	Object resolvedName = resolveStringValue(namedValueInfo.name);
	if (resolvedName == null) {
		throw new IllegalArgumentException(
				"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
	}

	Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
	if (arg == null) {
		if (namedValueInfo.defaultValue != null) {
			arg = resolveStringValue(namedValueInfo.defaultValue);
		}
		else if (namedValueInfo.required && !nestedParameter.isOptional()) {
			handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
		}
		arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
	}
	else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
		arg = resolveStringValue(namedValueInfo.defaultValue);
	}

	if (binderFactory != null) {
		WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
		try {
			arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
		}
		catch (ConversionNotSupportedException ex) {
			throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
					namedValueInfo.name, parameter, ex.getCause());
		}
		catch (TypeMismatchException ex) {
			throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
					namedValueInfo.name, parameter, ex.getCause());

		}
	}

	handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

	return arg;
}

//建立 NamedValueInfo
private NamedValueInfo getNamedValueInfo(MethodParameter parameter) {
	NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter);
	if (namedValueInfo == null) {
	    // 裏面 代碼是 new RequestParamNamedValueInfo();
	    //建立出來的 屬性 name value  都是空的
		namedValueInfo = createNamedValueInfo(parameter);
		// 給 namedValueInfo name 賦值 就是根據 parameter 的下標屬性 java反射 獲取參數名稱 ,東西太多了 不看了
		namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
		this.namedValueInfoCache.put(parameter, namedValueInfo);
	}
	return namedValueInfo;
}
<font color=#0034fff>//接着看主線代碼 </font>
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    //獲取了 namedValueInfo 三個屬性,name,defaultValue,required ,參數名,參數值,是否必須
    //如今 尚未參數值
	NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
	MethodParameter nestedParameter = parameter.nestedIfOptional();
	
    
	Object resolvedName = resolveStringValue(namedValueInfo.name);
	if (resolvedName == null) {
		throw new IllegalArgumentException(
				"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
	}
    //重點之一,獲取值,可是獲取的是個Object 類型的值 點進去看看 是如何獲取值的
	Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
	....................................

	handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

	return arg;
}

//獲取值,可是object類型的值
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
	HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);

	if (servletRequest != null) {
		Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
		if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
			return mpArg;
		}
	}

	Object arg = null;
	MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
	if (multipartRequest != null) {
		List<MultipartFile> files = multipartRequest.getFiles(name);
		if (!files.isEmpty()) {
			arg = (files.size() == 1 ? files.get(0) : files);
		}
	}
	if (arg == null) {
	    
	    <font color=#0034fff>// 看到了吧 是根絕getParameterValues獲取值,這個方法相信你們都很熟悉</font>
		String[] paramValues = request.getParameterValues(name);
		if (paramValues != null) {
			arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
		}
	}
	return arg;
}

<font color=#0034fff>//接着看主線代碼 </font>
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
	MethodParameter nestedParameter = parameter.nestedIfOptional();

	Object resolvedName = resolveStringValue(namedValueInfo.name);
	if (resolvedName == null) {
		throw new IllegalArgumentException(
				"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
	}
    //獲取值,上面說了這個值是 Object 類型的,全部說確定會有類型轉化的過程
	Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
	if (arg == null) {
		if (namedValueInfo.defaultValue != null) {
			arg = resolveStringValue(namedValueInfo.defaultValue);
		}
		else if (namedValueInfo.required && !nestedParameter.isOptional()) {
			handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
		}
		arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
	}
	else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
		arg = resolveStringValue(namedValueInfo.defaultValue);
	}

	if (binderFactory != null) {
		WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
		try {
		    //這裏作了類型轉化 點進去看下
			arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
		}
		catch (ConversionNotSupportedException ex) {
			throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
					namedValueInfo.name, parameter, ex.getCause());
		}
		catch (TypeMismatchException ex) {
			throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
					namedValueInfo.name, parameter, ex.getCause());

		}
	}

	handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

	return arg;
}

//最後來到了org.springframework.core.convert.support.ConversionUtils.invokeConverter(GenericConverter, Object, TypeDescriptor, TypeDescriptor)
@Override
@Nullable
public static Object invokeConverter(GenericConverter converter, @Nullable Object source,
			TypeDescriptor sourceType, TypeDescriptor targetType) {

	try {
	    //這裏 執行的  三個參數   值,元類型,目標類型
		return converter.convert(source, sourceType, targetType);
	}
	catch (ConversionFailedException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new ConversionFailedException(sourceType, targetType, source, ex);
	}
}


複製代碼

//spring 寫了好多類型之間的轉化器 數組

//隨便找一個點進去,你會發現用的也是jdk spring-mvc

ModelAttributeMethodProcessor(處理實體類參數)

//處理實體類參數
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
	Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
    //獲取實體類的名稱 
	String name = ModelFactory.getNameForParameter(parameter);
	ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
	if (ann != null) {
		mavContainer.setBinding(name, ann.binding());
	}

	Object attribute = null;
	BindingResult bindingResult = null;

	if (mavContainer.containsAttribute(name)) {
		attribute = mavContainer.getModel().get(name);
	}
	else {
		// Create attribute instance
		try {
		    <font color=#0034fff>//這裏要關注下,功能是建立你請求的實體類,假如你接收參數的實體類存在無參構造器則使用無參構造器
		    //假如沒有無參構造器,則使用有參構造器,並賦值.
		    //通常狀況都是無參構造器
		    //進入代碼看下
		    </font>
			attribute = createAttribute(name, parameter, binderFactory, webRequest);
		}
       ...............................................................
}
//建立請求實體參數,假如是有參構造器則同時賦值 (但也不必定所有屬性都賦值)
protected Object createAttribute(String attributeName, MethodParameter parameter,
			WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception {

	MethodParameter nestedParameter = parameter.nestedIfOptional();
	Class<?> clazz = nestedParameter.getNestedParameterType();
    //獲取默認構造器(無參構造器)
	Constructor<?> ctor = BeanUtils.findPrimaryConstructor(clazz);
	if (ctor == null) {
	    //假如沒有默認構造器,則獲取全部構造器
		Constructor<?>[] ctors = clazz.getConstructors();
		if (ctors.length == 1) {
		    //選擇第一個構造器
			ctor = ctors[0];
		}
		else {
			try {
				ctor = clazz.getDeclaredConstructor();
			}
			catch (NoSuchMethodException ex) {
				throw new IllegalStateException("No primary or default constructor found for " + clazz, ex);
			}
		}
	}
    //建立並賦值
	Object attribute = constructAttribute(ctor, attributeName, parameter, binderFactory, webRequest);
	if (parameter != nestedParameter) {
		attribute = Optional.of(attribute);
	}
	return attribute;
}

protected Object constructAttribute(Constructor<?> ctor, String attributeName, MethodParameter parameter,
			WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception {

	..................................................
	ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class);
	//獲取構造器 參數名稱
	String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor));
	Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor);
	Class<?>[] paramTypes = ctor.getParameterTypes();
	Assert.state(paramNames.length == paramTypes.length,
			() -> "Invalid number of parameter names: " + paramNames.length + " for constructor " + ctor);

	Object[] args = new Object[paramTypes.length];
	WebDataBinder binder = binderFactory.createBinder(webRequest, null, attributeName);
	String fieldDefaultPrefix = binder.getFieldDefaultPrefix();
	String fieldMarkerPrefix = binder.getFieldMarkerPrefix();
	boolean bindingFailure = false;
	Set<String> failedParams = new HashSet<>(4);
    //循環操做
	for (int i = 0; i < paramNames.length; i++) {
		String paramName = paramNames[i];
		Class<?> paramType = paramTypes[i];
		//仍是用的這個方法
		Object value = webRequest.getParameterValues(paramName);
		if (value == null) {
			if (fieldDefaultPrefix != null) {
				value = webRequest.getParameter(fieldDefaultPrefix + paramName);
			}
			if (value == null && fieldMarkerPrefix != null) {
				if (webRequest.getParameter(fieldMarkerPrefix + paramName) != null) {
					value = binder.getEmptyValue(paramType);
				}
			}
		}
		try {
			MethodParameter methodParam = new FieldAwareConstructorParameter(ctor, i, paramName);
			if (value == null && methodParam.isOptional()) {
				args[i] = (methodParam.getParameterType() == Optional.class ? Optional.empty() : null);
			}
			else {
			    //去綁定,就是去作類型轉化,裏面的參數就個 上面講的同樣了,就不說了.
				args[i] = binder.convertIfNecessary(value, paramType, methodParam);
			}
		}
	..........................................................................

<font color=#0034fff>//回到主線</font>
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

    ...................................................
    
	if (mavContainer.containsAttribute(name)) {
		attribute = mavContainer.getModel().get(name);
	}
	else {
		// Create attribute instance
		try {
		    //獲取 請求類型 實例
			attribute = createAttribute(name, parameter, binderFactory, webRequest);
		}
		catch (BindException ex) {
			if (isBindExceptionRequired(parameter)) {
				// No BindingResult parameter -> fail with BindException
				throw ex;
			}
			// Otherwise, expose null/empty value and associated BindingResult
			if (parameter.getParameterType() == Optional.class) {
				attribute = Optional.empty();
			}
			bindingResult = ex.getBindingResult();
		}
	}

	if (bindingResult == null) {
		// Bean property binding and validation;
		// skipped in case of binding failure on construction.
		WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
		if (binder.getTarget() != null) {
			if (!mavContainer.isBindingDisabled(name)) {
			    //這個方法 重要 賦值 在裏面完成的
				bindRequestParameters(binder, webRequest);
			}
			validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
				throw new BindException(binder.getBindingResult());
			}
		}
		// Value type adaptation, also covering java.util.Optional
		if (!parameter.getParameterType().isInstance(attribute)) {
			attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
		}
		bindingResult = binder.getBindingResult();
	}

	// Add resolved attribute and BindingResult at the end of the model
	Map<String, Object> bindingResultModel = bindingResult.getModel();
	mavContainer.removeAttributes(bindingResultModel);
	mavContainer.addAllAttributes(bindingResultModel);

	return attribute;
}
//賦值 和類型轉換
public void bind(ServletRequest request) {
    //這個裏面完成的獲取值  可是還沒賦值
	MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
	MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
	if (multipartRequest != null) {
		bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
	}
	addBindValues(mpvs, request);
	//完成的綁定   就不看了   這篇說的太多了,不想繼續寫了.
	doBind(mpvs);
}

public ServletRequestParameterPropertyValues(
		ServletRequest request, @Nullable String prefix, @Nullable String prefixSeparator) {

	super(WebUtils.getParametersStartingWith(
			request, (prefix != null ? prefix + prefixSeparator : null)));
}
//獲取值的方法  到這裏也就沒有了.
public static Map<String, Object> getParametersStartingWith(ServletRequest request, @Nullable String prefix) {
	Assert.notNull(request, "Request must not be null");
	//獲取全部參數
	Enumeration<String> paramNames = request.getParameterNames();
	Map<String, Object> params = new TreeMap<>();
	if (prefix == null) {
		prefix = "";
	}
	while (paramNames != null && paramNames.hasMoreElements()) {
		String paramName = paramNames.nextElement();
		if ("".equals(prefix) || paramName.startsWith(prefix)) {
			String unprefixed = paramName.substring(prefix.length());
			//獲取值   都是用的getParameterValues
			String[] values = request.getParameterValues(paramName);
			if (values == null || values.length == 0) {
				// Do nothing, no values found at all.
			}
			else if (values.length > 1) {
				params.put(unprefixed, values);
			}
			else {
				params.put(unprefixed, values[0]);
			}
		}
	}
	return params;
}

複製代碼

執行流程繼續 主線

其實剩下的東西沒啥要說的了,就是貼下代碼吧緩存

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    //上面 這麼多 都是說這行代碼 就是獲取到了請求參數,而且保證了順序
	Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
	if (logger.isTraceEnabled()) {
		logger.trace("Arguments: " + Arrays.toString(args));
	}
	//執行
	return doInvoke(args);
}

@Nullable
protected Object doInvoke(Object... args) throws Exception {
	ReflectionUtils.makeAccessible(getBridgedMethod());
	try {
	    //這裏 結束了 調用了方法 使用的是 java 的 反射
		return getBridgedMethod().invoke(getBean(), args);
	}
	catch (IllegalArgumentException ex) {
		assertTargetBean(getBridgedMethod(), getBean(), args);
		String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
		throw new IllegalStateException(formatInvokeError(text, args), ex);
	}
	catch (InvocationTargetException ex) {
		// Unwrap for HandlerExceptionResolvers ...
		Throwable targetException = ex.getTargetException();
		if (targetException instanceof RuntimeException) {
			throw (RuntimeException) targetException;
		}
		else if (targetException instanceof Error) {
			throw (Error) targetException;
		}
		else if (targetException instanceof Exception) {
			throw (Exception) targetException;
		}
		else {
			throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
		}
	}
}
複製代碼

總結

  1. 正常的請求(controller)的原理是java的反射
  2. spring保存了請求方法和對應路徑
  3. 請求的時候獲取參數的過程很難,類型也不少
  4. 獲取參數都是使用 HttpServletRequest 的相關獲取參數的方法
  5. 會作一個類型轉換,例如你接收一個Integer,可是剛到spring的時候類型是string,spring本身作的作換,因此說假如不符合java類型轉化的規則會報錯. 例如 接收參數 Integer age 你傳值 sb 會報錯,這個錯實際上是java報的.
相關文章
相關標籤/搜索