springmvc源码---springmvc的核心流程(请求发起到执行完)

SpringMVC源码:核心流程

从请求发起到执行完Controller方法为止

来说一下怎么看源码:
我们知道SpringMVC的核心就是DispatcherServlet,那么本质就是Servlet,我们要看请求的处理,可以直接去找doGetdoPost方法。经过查找可以发现,在DispatcherServlet没有这两个方法,而在它的父类FrameworkServlet有这两个方法。
以doGet为例 可以看到它其实就是调用了processRequest(request, response);(其实 get post put delete四个方法的方法体都是这一句话

	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

我们进入processRequest(request, response);方法,可以看到里面最核心的代码就是doService(request, response);这个方法是个抽象方法,其实现里面也只有一个核心的代码就是doDispatch(request, response);所以我们直接接入doDispatch方法查看逻辑。上述doService都是和doDispatch否是FrameworkServlet的抽象方法,FrameworkServlet的象方法doDispatch的实现在DispatcherServlet里。

doDispatch源码如下:

	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 {
				/* *先来看这行代码 Multipart我们知道是用来上传文件的
				*所以这个就是检查你的请求有没有附带文件
				 本质是检查你的请求头的Content-Type看下是不是一个文件类型
				*/
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				//getHandler这是一个非常核心的方法
				//找Controller
				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);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

来看getHandler的源码: 获取Controller的

	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		//handlerMappings 默认会有两个handlerMapping 是用来获取handler 即Controller的
		//如果我们自己实现了WebMvcConfig的接口 自定义了handler 那么也会在这里
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

来看上述的mapping.getHandler(request);

	@Override
	@Nullable
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		Object handler = getHandlerInternal(request);

再进入getHandlerInternal(request);

	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		//lookupPath 就是我们Controller上的URI
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		this.mappingRegistry.acquireReadLock();
		try {
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}

来看lookupHandlerMethod(lookupPath, request);

	@Nullable
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<>();
		//注意这行代码
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);

来看this.mappingRegistry.getMappingsByUrl(lookupPath);

		@Nullable
		public List<T> getMappingsByUrl(String urlPath) {
			return this.urlLookup.get(urlPath);
		}

可以看到最底层就只是一个名为urlLookup的Map,里面存储了请求的URI(key)和请求方法RequestMappingInfo(value)信息
所以接下来要研究这些值是什么时候放到Map里去的,使用IDEA对这个urlLookup FindUasges
可以找到在一个register方法中add了值,然后我们一路使用这种方法往上找,找到这个方法最早什么时候开始的。最终找到AbstractHandlerMethodMapping的afterPropertiesSet方法。afterPropertiesSet是InitializingBean接口里面的唯一方法,会在spring加载完Bean之后调用

@Override
public void afterPropertiesSet() {
	initHandlerMethods();
}

来看initHandlerMethods()

	protected void initHandlerMethods() {
		//getCandidateBeanNames拿到所有beanName
		for (String beanName : getCandidateBeanNames()) {
		//SCOPED_TARGET_NAME_PREFIX的值是scopedTarget. 目前不知道作用
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				processCandidateBean(beanName);
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

----------------getCandidateBeanNames的代码直接贴在这里------------------
		protected String[] getCandidateBeanNames() {
		//detectHandlerMethodsInAncestorContexts 默认是false 除非用户自己修改
		//这里牵扯到一个spring父子容器的知识 下节课讲
		return (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
				//最终拿到所有的beanName
				obtainApplicationContext().getBeanNamesForType(Object.class));
	}

-----------processCandidateBean方法贴在这里-------------------------
	protected void processCandidateBean(String beanName) {
		Class<?> beanType = null;
		try {
		//根据BeanName拿到该beanName对应的类
			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);
			}
		}
		//isHandler判断上面有没有加@Controller和@RequestMapping注解
		if (beanType != null && isHandler(beanType)) {
		//遍历里面所有的方法
			detectHandlerMethods(beanName);
		}
	}
------------------------detectHandlerMethods的源码贴在这里--------------
	protected void detectHandlerMethods(Object handler) {
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());

		if (handlerType != null) {
			Class<?> userType = ClassUtils.getUserClass(handlerType);
			//遍历当前传入的类的所有方法对象
			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
						try {
							//接下来注意这个方法 根据method以及RequestMapping注解生成
							//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) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}
--------------------getMappingForMethod源码贴在这里------------

	@Override
	@Nullable
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		//接下来注意这个方法 根据method以及RequestMapping注解生成
		//RequestMappingInfo对象
		RequestMappingInfo info = createRequestMappingInfo(method);
		if (info != null) {
			RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
			if (typeInfo != null) {
				info = typeInfo.combine(info);
			}
			String prefix = getPathPrefix(handlerType);
			if (prefix != null) {
				info = RequestMappingInfo.paths(prefix).build().combine(info);
			}
		}
		return info;
	}

----------------------	createRequestMappingInfo源码贴在这里---------------------
	@Nullable
	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		//判断方法上有没有加@RequestMapping注解
		RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
		//如果加了 判断有没有自定义的RequestCondition对象 RequestCondition即自定义匹配请求
		//条件	一般情况下是没有的 直接根据URI(/test.do)就能访问
		//如果自定义了 比如不仅需要/test.do ,还需要头信息里包含XXX等等
		//RequestCondition接口里主要有三个方法
		//T combine(T other) :如果你要重写多个RequestCondition  调用这个
		//T getMatchingCondition(HttpServletRequest request):这个方法传给你了一个请求对象,你可以在这里做处理 这是真正自定义请求匹配条件的方法
		//int compareTo(T other, HttpServletRequest request);
		RequestCondition<?> condition = (element instanceof Class ?
				getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
		//如果方法上加了@RequestMapping 那就返回 RequestMappingInfo   没有就返回null
		return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
	}
-----------------createRequestMappingInfo(requestMapping, condition)源码如下------
	protected RequestMappingInfo createRequestMappingInfo(
			RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

		RequestMappingInfo.Builder builder = RequestMappingInfo
				.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
				.methods(requestMapping.method())
				.params(requestMapping.params())
				.headers(requestMapping.headers())
				.consumes(requestMapping.consumes())
				.produces(requestMapping.produces())
				.mappingName(requestMapping.name());
		if (customCondition != null) {
			builder.customCondition(customCondition);
		}
		return builder.options(this.config).build();
	}

上述分析完了创造RequestMappingInfo的过程,接下来我们回到detectHandlerMethods方法的

//这里是对类中所有方法的遍历
methods.forEach((method, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				//会将方法注册到一个名叫mappingRegistry的对象中
				registerHandlerMethod(handler, invocableMethod, mapping);
			});

------------registerHandlerMethod源码如下---------------------
		protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		//这里既是一开始我们找到的存放URI和RequestMappingInfo的Map的put的地方
		this.mappingRegistry.register(mapping, handler, method);
	}

--------------this.mappingRegistry.register代码如下--------------
		public void register(T mapping, Object handler, Method method) {
			this.readWriteLock.writeLock().lock();
			try {
				HandlerMethod handlerMethod = createHandlerMethod(handler, method);
				assertUniqueMethodMapping(handlerMethod, mapping);
				//这个就是我们一开始找到的map
				this.mappingLookup.put(mapping, handlerMethod);

				List<String> directUrls = getDirectUrls(mapping);
				for (String url : directUrls) {
					this.urlLookup.add(url, mapping);
				}

				String name = null;
				if (getNamingStrategy() != null) {
					name = getNamingStrategy().getName(handlerMethod, mapping);
					addMappingName(name, handlerMethod);
				}

				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();
			}
		}

到这一步 上述的getHandler的流程就通了,总结一下上述流程就是
1.扫描整个项目 这个是由spring帮做的,然后利用spring的beanName找到类
2.判断有没有@Controller和@RequestMapping注解
3.扫描方法
4.判断方法上有没有@RequestMapping注解
5.有的话封装成一个RequestMappingInfo对象
6.put到名为urlLookup的map中

继续往下分析,回到一开始的getHandler方法

	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	//回来思考这里的handlerMappings 这是springmvc的一个扩展点,mvc自己自带的有,也可以有用户扩展的
	//springmvc之所以自己要定义多个handlerMapping 是因为注册Controller有多种方式,见下面
	//spring自己定义的handlerMapping有RequestMappingHandlerMapping和BeanNameUrlHandlerMapping 其中后者就是处理下方描述的第3种方式
	//注意 BeanNameUrlHandlerMapping 的对应的map不是上述的urlLookup 而是handlerMap
	//也就是不同的Controller会放到不同的map中去 最终的处理方式也不同
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
			//HandlerExecutionChain 等于是Controller对象加上拦截器
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

在这里讲一下有哪几种方式注册Controller
1.在类上加@Controller注解
2.写一个类 实现Controller接口 注意 就是Controller接口 不是注解
3.写一个类 实现HttpRequestHandler,这种方式的类要放到Spring容器中去,比如@Component(/url) 注意括号里必须是路径,而不是传统的Spring的beanName 这是个比较传的方式,相当于一个类只能是一个方法,现在基本不用了。


上述讲到了handlerMappings其实是SpringMVC的一个扩展点,讲到这里其实已经可以理解为什么SpringMVC访问不到静态资源了,因为SpringMVC没有给我们去加载静态资源(handlerMappings里没有保存静态资源),我们可以自己写一个handlerMapping来加载静态资源。一个请求 怎么去找到一个handler? 所谓handler就是请求的一个返回对象,可以是一个Controller类,也可以是一个方法,所以你也可以返回一个视图,就是你这请求就是返回一个静态资源。你可以重写一个HandlerMapping,通过实现HandlerMapping接口的方式。
那么怎么让你写的类存入到上述的handlerMappings里面
handlerMappings实际上是在DispatcherServlet的initStrategies里初始化的,initStrategies这个方法会被DispatcherServlet的初始化WebApplicationContext的时候方法调用到。initStrategies的作用就是初始化一些组件,包含上面说到的handlerMappings

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

initHandlerMappings(context);会解析webmvc jar包下的servlet包的DispatcherServlet.properties配置文件,通过改这个配置文件加入我们自己写的类是可以的 但是这个配置我们我们改不了。所以我们可以通过把我们自己写的类加入到Spring容器里去
来看initHandlerMappings的源码

	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			//这里会根据HandlerMapping类型拿到一个HandlerMapping 最后会放到上述的handlerMappings map中去 这样就实现了自定义HandlerMapping。
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);

SpringBoot之所以能访问到一个静态资源,那就是因为它重写了一个HandlerMapping。最终通过response.getWriter写出去的。具体处理静态资源的handler叫SimpleUrlHandlerMapping。我们可以通过打断点的方式去看。SimpleUrlHandlerMapping会找到你的请求映射到哪个静态目录下,这些静态目录就是我们说的SpringBoot中的四个有先后 顺序的静态目录。
1.META-INF/reosurces
2.resources/
3.static/
4.public/
找到资源后,最终在mv = ha.handle 这个处理请求的操作中,会把静态资源通过流写出去,当然不是每请求一次就写一次,这样太耗费资源,会利用到缓存。这个缓存毁三观,利用了浏览器的缓存,它响应一个状态码304,告诉浏览器,它当前返回的这个资源可以缓存,下一次访问就走缓存。

上述为SpringMVC怎么找到的Handler,那么如何处理handler?

继续接getHandler之后的代码

				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					//如果是空 返回404页面
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				//这里是拿到适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());


--------------getHandlerAdapter的代码如下------------------------------------
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		//默认的适配器有三个
		//RequestMappingHandlerAdapter
		//HttpRequestHandlerAdapter
		//SimpleControllerHandlerAdapter
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
			//supports方法应对不同实现方式实现的Controller有不同的处理方案
				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");
	}

springmvc 有两种类型的Controller:注解 和 beanName
这两种类型的Controller有3种实现方式
两大类型由上述说的两种HandlerMapping来处理,3种实现对应三种HandlerAdapter
RequestMappingHandlerAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter

思考:Java调用一个方法,有哪几种方式?
1.new 对象。方法名
2.定义一个接口,需要调用的类实现目标接口,直接调用接口的实现方法
3.目标对象是一个Servlet 可以把请求转还发给对应的servlet来调用
4.反射

上述通过beanName方式实现的Controller,是实现了HttpRequestHandler接口或Controller,调用接口的实现方法。
但是以注解的方式实现的Controller,只能通过反射来调用方法

我们回到上述代码的supports方法,有以下几种处理方案

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				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");
	}

-----------------supports方法的处理方案如下----------------------------------
1.处理注解方式
	@Override
	public final boolean supports(Object handler) {
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}

2.处理实现了HttpRequestHandler接口的
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof HttpRequestHandler);
	}
3.处理实现了Controller接口的
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}
4.处理实现了servlet接口的
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Servlet);
	}

我们回到doDispatcher方法

	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.
				//获取handler
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				//获取handlerAdapter
				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.
				//这里是在执行handler 同样是上述四种handlerAdapter的四种方法 根据Controller的实现方式不同 handler方法也有区别 策略模式
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

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

我们来看最关键的注解方式的handler的执行方法

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

方法调用链:
handle->handleInternal->invokeHandlerMethod->invokeAndHandle->invokeForRequest->getMethodArgumentValues

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

		//拿到形参数组
		MethodParameter[] parameters = getMethodParameters();
		if (ObjectUtils.isEmpty(parameters)) {
			return EMPTY_ARGS;
		}
		//拿到实参数组
		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;
			}
			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 exMsg = ex.getMessage();
					if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
						logger.debug(formatArgumentError(parameter, exMsg));
					}
				}
				throw ex;
			}
		}
		return args;
	}

调用链resolveArgument ->getArgumentResolver
这里对不同类型的参数用了不同的Resolver去处理,算是一种适配器模式,这种处理方式是靠实现HandlerMethodArgumentResolver接口实现的
注意:这里也是一个扩展点,我们可以自定义参数类型,然后自定义一个ArgumentResolver实现然后加入一个HandlerMethodArgumentResolver接口,并且把自定义的ArgumentResolver放入resolvers的list里面,操作如下:

public class AppConfig implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
			resolvers.add(new ArgumentResolver);
    }
}

这样SpringMVC就可以按我们的自定义的方式处理我们自定义的参数类型。

最终调用我们的Controller方法是在 invokeForRequest ->doInvoke->getBridgedMethod().invoke(getBean(), args);这一步。
可以看到getBean() 是直接去spring容器里面去拿bean ,拿到对象和参数后,就可以执行我们的方法了

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值