从源码角度分析SpringMVC执行流程

发布于:2025-02-10 ⋅ 阅读:(33) ⋅ 点赞:(0)

一、SpringMVC基本概述

SpringMVC是基于Servlet进行的封装框架,是一个Spring框架的一个模块。它以SpringIOC容器为基础,并利用容器的特性来简化它的配置,所以 SpringMVC Spring 可直接整合使用。
SpringMVC也是一个容器,使用IoC核心技术,管理界面层中的控制器对象。SpringMVC的底层就是servlet,以servlet为核心,接收请求、处理请求,显示处理结果给用户。在此之前这个功能是由Servlet来实现的,现在使用SpringMVC来代替Servlet行驶控制器的角色和功能。其核心Servlet是:DispatcherServlet。

SpringMVC中的核心组件:

  1. 前端控制器:DispatcherServlet,本质是一个Servlet,底层实质是继承了HttpServlet,用于接受请求,响应结果,相当于是转发器,是SpringMVC框架中最核心的组件,有了它就能减少其他组件之间的耦合度
  2. 处理器映射器HandlerMapping,专门负责映射的,根据请求路径去映射处理器方法。
  3. 处理器适配器HandlerAdapter,适配调用具体的处理器,解析请求中的参数,并且执行处理器中的方法,执行完成之后返回一个ModelAndView对象。
  4. 处理器Handler,就是我们写的方法。
  5. 视图解析器ViewResolver,会根据传递过来的ModelAndView对象进行视图解析,根据视图逻辑名称装换成为视图的物理名称View
  6. 视图View是一个接口,它的实现类支持不同类型的视图。比如:JSP、freemarker、Thymeleaf等等。

二、SpringMVC的执行流程

在这里插入图片描述

  1. 用户发送请求,根据请求会分发到DispatcherServlet中。
  2. DispatcherServlet会根据请求Request的请求路径以及请求方式找到处理器Handler并且返回。底层实质返回的是一个HandlerExecutionChain处理器执行链对象,里面封装了本次请求要执行的处理器方法以及所有的拦截器。
  3. DispatcherServlet根据Handler匹配到对应的处理器适配器HandlerAdapter,实现方式是循环遍历DispatcherServlet中的所有处理器适配器,根据Handler的类型进行适配。
  4. 执行本次请求所有拦截器的preHandle方法。
  5. 调用处理器适配器的handle方法,处理器适配器会从请求中获取参数,执行处理器方法,并且最终返回一个ModelAndView对象。
  6. 执行本次请求所有拦截器的postHandle方法。
  7. 通过视图解析器对ModelAndView进行解析,将响应视图的逻辑位置解析成真正的物理位置,并且返回View对象。
  8. 视图进行渲染,并且执行本次请求的所有拦截器的afterCompletion方法。
  9. 响应给前端。

三、SpringMVC源码的执行流程

DispatcherServlet前端控制器

public class DispatcherServlet extends FrameworkServlet {
	//初始化的时候会将所有HandlerMapping都封装在这个List里面
	private List<HandlerMapping> handlerMappings;
	
	// 前端控制器最核心的方法,这个方法是负责处理请求的,每次发送请求时,都会调用这个方法,这个方法实质是FrameworkServlet继承了HttpServlet,重写其service(HttpServletRequest req, HttpServletResponse resp)方法
	protected void doDispatch(HttpServletRequest processedRequest, HttpServletResponse response) throws Exception {
		//根据请求路径,来获取对应的要执行的处理器,其本质是通过请求的uri和请求方式进行匹配到对应的处理器
		//返回的是一个处理器执行链对象,这个对象就是本次请求所要执行的所有拦截器和处理器
		//本质是通过调用HandlerMapping的handler方法
		//HandlerExecutionChain是一次请求一个对象
		HandlerExecutionChain mappedHandler mappedHandler = getHandler(processedRequest);
		
		//根据处理器获取处理器适配器
		//Handler实质就是我们写的方法
		HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
		
		//执行该请求对应的所有拦截器的preHandler方法
		if (!mappedHandler.applyPreHandle(processedRequest, response)) {
			return;
		}
		//调用处理器方法,返回ModelAndView
		//在执行处理器方法之前,需要给处理器方法传参数,这个方法会对处理器进行数据绑定,即将请求参数封装到处理器方法中
		mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
		
		//执行该请求所有拦截器中的postHandle方法
		mappedHandler.applyPostHandle(processedRequest, response, mv);
		
		//处理分发结果,本质就是响应结果到浏览器
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}

	//处理分发结果
	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
				
		//渲染
		render(mv, request, response);	
		
		//执行该请求所有拦截器中的afterCompletion方法
		mappedHandler.triggerAfterCompletion(request, response, null);
	}
	
	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		//通过视图解析器进行解析,返回视图View对象
		View view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
		
		//调用视图对象的渲染方法,完成响应
		view.render(mv.getModelInternal(), request, response);
	}
	
	//解析视图名称
	protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
			HttpServletRequest request) throws Exception {
		//可以配置多个视图解析器,例如ThymeleafViewResolver,InternalResourceViewResolver......
		for (ViewResolver viewResolver : this.viewResolvers) {
			//通过视图解析器进行解析,返回视图对象View
			View view = viewResolver.resolveViewName(viewName, locale);
			if (view != null) {
				return view;
			}
		}
		return null;
	}
}

视图解析器接口

// 视图解析器有很多实现类,例如ThymeleafViewResolver,InternalResourceViewResolver......
public interface ViewResolver {
	//根据视图逻辑名称获取视图物理名称,返回视图对象
	View resolveViewName(String viewName, Locale locale) throws Exception;
}

视图接口

//视图接口,例如实现类ThymeleafView,InternalResourceView......
public interface View {
	//这里是真正的渲染
	void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}

DispatcherServlet执行原理

在这里插入图片描述

总结:

  1. 浏览器发送请求,根据配置的web.xml文件找到DispatcherServlet
  2. DispatcherServlet实质是继承了HttpServlet,重写其service方法,service方法然后调用DispatcherServlet最核心的doDispatch方法
  3. doDispatch方法首先会根据请求Request信息,根据请求路径,来获取对应的要执行的处理器,实质返回的是一个处理器执行链
    • 什么是处理器映射器(HandlerMapping)?
      专门负责映射的,根据请求路径去映射处理器方法。
      下面有很多实现类,例如专门处理@RequestMapping注解的RequestMappingHandlerMapping
      SpringMVC初始化处理器映射器会解析所有带有@Controller的类,将所有带有@RequestMapping和其延申注解(@GetMapping@PostMapping)的方法封装成HandlerMethod对象并且以Map形式封装在处理器映射器中。同时所有的拦截器也会封装在拦截器处理器中。

    • 什么是执行链?
      HandlerExecutionChain:里面封装了这次请求对应的处理器方法,以及这次请求的所有要执行的拦截器。

    • 什么是处理器方法?
      HandlerMethod:里面封装了我们Controller的字节码、Controller对应方法的Method对象以及需要执行方法所需的参数。

    • 如何获取执行链的:
      因为HandlerMapping在SpringMVC启动的时候就已经初始化好了,HandlerMapping内部其实是根据请求的uri与所有的HandlerMethod进行匹配,同理拦截器也是如此。具体实现方式可以参考本文AbstractHandlerMapping部分源码。

四、前端控制器根据请求获取处理器原理

获取处理器代码 HandlerExecutionChain mappedHandler mappedHandler = getHandler(processedRequest);

前端控制器 DispatcherServlet

//前端控制器,SpringMVC最核心的类
public class DispatcherServlet extends FrameworkServlet {
	//在我们SpringMVC有多种Handler实现方式,有通过@RequestMapping注解,也有通过继承HttpRequestHandler来实现的,
	//针对不同的Handler会有不同的HandlerMapping来进行处理。使用注解对应的处理器映射器是RequestMappingHandlerMapping,
	//使用HttpRequestHandler继承对应的处理器映射器是BeanNameUrlHandlerMapping。
	//SpringMVC初始化的时候会将所有HandlerMapping都封装在这个List里面
	private List<HandlerMapping> handlerMappings;
	
	//根据请求获取处理器,实质返回的是一个处理器执行链
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		//遍历所有的处理器映射器
		for (HandlerMapping mapping : this.handlerMappings) {
			//调用HandlerMapping的getHandler方法匹配对应的处理器和拦截器
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}
}

处理器映射 HandlerMapping

/**
 * 处理器映射器,专门负责映射的,根据请求路径去映射处理器方法
 * 这个接口下面有很多实现类,使用注解对应的处理器映射器是RequestMappingHandlerMapping。
 * 使用HttpRequestHandler继承对应的处理器映射器是BeanNameUrlHandlerMapping。
 */
public interface HandlerMapping {
	//根据请求信息,获取处理器执行链
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

处理器映射器抽象类 AbstractHandlerMapping

/**
 * 处理器映射抽象类
 * 本文仅对RequestMappingHandlerMapping处理器映射器进行源码解读
 */
public abstract class AbstractHandlerMapping implements HandlerMapping{
	//所有拦截器,SpringMVC初始化的时候会把所有的拦截器都放在这个List里面
	private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();
	
	//根据请求查询处理器执行链
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		//实质是调用AbstractHandlerMethodMapping的getHandlerInternal方法
		//实质获取的是处理器方法RequestMethod对象
		Object handler = getHandlerInternal(request);
		//这个方法会去匹配拦截器,并且将一次请求所有要执行的拦截器和处理器方法封装起来返回一个处理器执行链
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		return executionChain;
	}
	
	//匹配拦截器
	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		//创建一个处理器执行链
		HandlerExecutionChain chain = new HandlerExecutionChain(handler);
		//获取请求uri
		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		//遍历循环所有拦截器
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
			//拦截器根据当前请求uri进行和拦截器配置的拦截路径匹配
			if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
				//将拦截器加入到处理器执行链中
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}
	}
}

处理器方法映射抽象类 AbstractHandlerMethodMapping

public abstract class AbstractHandlerMethodMapping<T>  extends AbstractHandlerMapping{	

	//SpringMVC初始化的时候会对这里进行处理,将所有处理器加载进来
	private final MappingRegistry mappingRegistry = new MappingRegistry();
	
	//内部类
	class MappingRegistry {
			private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();
			
			//SpringMVC初始化的时候做了处理,将所有的处理器都进行封装成了uri->List<RequestMappingInfo>格式的Map
			//RequestMappingInfo是请求映射详情,里面封装了每个处理器的详细信息,比如请求方式,请求路径,请求所需要的参数等等
			//RequestMappingInfo提供了一个getMatchingCondition(HttpServletRequest request)方法,根据请求判断是否与这个映射匹配,其本质就是根据Request中的请求信息与ReqeustMappingInfo的信息进行逐一比较。
			private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();
	
			//SpringMVC初始化的时候做了处理,将所有的处理器封装成了RequestMappingInfo->HandlerMethod格式的Map,方便查找。
			private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();
	
			//根据请求的uri,获取对应的请求映射详情RequestMappingInfo
			public List<T> getMappingsByUrl(String urlPath) {
				return this.urlLookup.get(urlPath);
			}
			
			//根据请求映射详情ReqeustMappingInfo获取处理器方法
			public Map<T, HandlerMethod> getMappings() {
				return this.mappingLookup;
			}
	}
	
	//映射注册,处理器的各种信息封装在里面
	private static class MappingRegistration<T> {
		//在使用@RequestMapping注解方式情况下,这里实质是一个ReqeustMappingInfo
		private final T mapping;
		//处理器方法
		private final HandlerMethod handlerMethod;
		//映射路径
		private final List<String> directUrls;
		private final String mappingName;
	}
	
	//根据请求获取对应的处理器
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		//根据请求获取请求uri
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		//根据请求的uri匹配处理器方法
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	
	//根据请求路径匹配处理器器方法
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<Match>();
		//根据请求uri,获取匹配的RequestMappingInfo,由于同一个uri存在相同的处理器,所以这里返回的是List
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
		
		//再根据当前请求进行匹配(其实就是根据请求参数,请求方式等进行过滤RequestMappingInfo,然后根据RequestMappingInfo找到映射方法HandlerMethod),并且封装到matches集合里面
		addMatchingMappings(directPathMatches, matches, request);
		//其实这里省略了bestMatch 的长度判断,如果大于1会报错。
		Match bestMatch = matches.get(0);
		//返回HandlerMethod对象
		return bestMatch.handlerMethod;
		
	}
	
	//根据请求信息获取匹配的处理器方法,并且封装成Match对象加入matches集合中
	private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
		//针对注解实现的方式,这里的泛型就是ReqeustMappingInfo
		//遍历传入的请求映射详情
		for (T mapping : mappings) {
			//根据RequestMappingInfo和请求信息进行匹对,判断当前映射是否满足请求。
			T match = getMatchingMapping(mapping, request);
			if (match != null) {
				//根据请求映射详情RequestMappingInfo找到处理器方法HandlerMethod,并且创建一个Matche对象封装到集合中
				matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
			}
		}
	}
	
	//映射工具类
	private class Match {
		private final T mapping;
		private final HandlerMethod handlerMethod;
	}
}
  • RequestMappingInfoHandlerMapping
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
	//根据请求信息和RequestMappingInfo判断当前请求映射是否匹配此次请求,如果符合返回该请求映射
	//注意,由于请求映射在项目初始化的时候就已经创建了,但是返回的时候是采用创建一个新的RequestMappingInfo对象返回的
	protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
		return info.getMatchingCondition(request);
	}
}
  • RequestMappingHandlerMapping
//请求映射处理器,针对使用了@RequestMapping注解的请求方式
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
			
}
  • 请求映射详情 RequestMappingInfo
//这个类是请求映射详情,里面封装了需要执行处理器所需要的信息,比如请求方式,请求参数
//比如我们定义了  @RequestMapping(value = "/user/findUserById",method = RequestMethod.GET)
//那么methodsCondition里面就是GET,这个类就是将我们写的Controller所需要的请求方式,请求rui,请求参数进行封装
public final class RequestMappingInfo{
	
	//下面这些变量都是这个请求映射执行所需要的参数信息封装在这里
	private final PatternsRequestCondition patternsCondition;

	private final RequestMethodsRequestCondition methodsCondition;

	private final ParamsRequestCondition paramsCondition;

	private final HeadersRequestCondition headersCondition;

	private final ConsumesRequestCondition consumesCondition;

	private final ProducesRequestCondition producesCondition;

	private final RequestConditionHolder customConditionHolder;

	//根据请求信息,判断当前的RequestMappingInfo是否满足请求,如果请求就返回一个RequestMappingInfo,如果不满足返回null
	public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
		//根据请求判断当前的请求是否和requestMappingInfo对象的请求一致,底层逻辑就是request.getMethod方法获取当前请求方式
		RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
		ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
		HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
		ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
		ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);

		if (methods == null || params == null || headers == null || consumes == null || produces == null) {
			return null;
		}

		PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
		if (patterns == null) {
			return null;
		}

		RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
		if (custom == null) {
			return null;
		}
		//如果一致,这里创建一个对象返回
		return new RequestMappingInfo(this.name, patterns,
				methods, params, headers, consumes, produces, custom.getCondition());
	}
}

HandlerExecutionChain 处理器执行链

//处理器链执行链
public class HandlerExecutionChain {
	//处理器,就是我们写的方法
	//这里使用Object的原因是因为处理器有很多种,
	//如果使用的是@RequestMapping注解的方式,底层实质是一个处理器方法对象HandlerMethod,这个处理器方法对象封装了名称以及对应的处理器方法
	//HandlerMethod:处理器方法是在web服务器启动时初始化就创建好了的,这个类当中比较重要的属性包括:beanName和Method方法
	//如果我们是采用继承HttpRequestHandler方式,这个handler就是我们写的Controller,实质还是一个HttpRequestHandler
	private final Object handler;
	
	//该请求对应的所有拦截器按照顺序放到了List集合中
	private List<HandlerInterceptor> interceptorList;
	
	//拦截器下标
	private int interceptorIndex = -1;
}

//处理器方法,这个是专门针对@RequestMapping注解的方式,里面封装了我们写的方法信息
public class HandlerMethod {
	
	//执行方法所有的类字节码
	private final Class<?> beanType;
	
	//实际要执行的方法
	private final Method method;
	
	//处理器方法所有请求参数信息
	private final MethodParameter[] parameters;
}

SpringMVC初始化处理器的结构

在这里插入图片描述

总结:

  1. SpringMVC实现处理器的方式有多种,针对不同的方式会有多种不同的处理器映射器。比如使用注解@RequstMapping实现处理器的处理器映射器就是RequestMappingHandlerMapping
  2. SpingMVC初始化的时候会将所有的处理器映射器都创建出来,并且放到DispacherServlethandlerMappings变量里。
  3. 针对RequestMappingHandlerMapping处理器初始化时,会将所有的处理器基本信息如请求地址,请求方式,请求参数等封装成RequestMappingInfo对象。将所有处理器的类字节码Class<?> beanType,请求方法Method,请求参数MethodParameter[] parameters封装成为HandlerMethod对象。然后将RequestMappingInfo作为key,HandlerMethod作为Value封装为Map放在处理器映射器的变量里。
  4. 创建RequestMappingHandlerMapping的同时,会将所有的拦截器放在处理器映射器变量中。
  5. 前端控制器循环遍历所有处理器映射器HandlerMapping,并且调用其中getHandler方法匹配对应的处理器。
  6. getHandler方法会根据请求uri,获取对应的RequestMappingInfo,然后再根据RequestMappingInfo作为key获取到处理器方法HandlerMethod`并且返回。
  7. 循环遍历所有的拦截器,并且根据当前请求路径与拦截器配置的路径相匹配,拿到本次请求要执行的所有拦截器集合。
  8. 将处理器方法和本次请求所有要执行的拦截器封装成拦截器执行链HandlerExecutionChain

五、如何根据处理器获取处理器适配器

获取处理器适配器HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

前端控制器 DispatcherServlet

//前端控制器,SpringMVC最核心的类
public class DispatcherServlet extends FrameworkServlet {
	
	private List<HandlerMapping> handlerMappings;
	
	//SpringMVC初始化的时候会将所有的处理器适配器创建出来,并且封装到handlerAdapters中
	private List<HandlerAdapter> handlerAdapters;
	
	//根据处理器获取对应的处理器适配器
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		//遍历适配器,不同处理器的适配器不一样
		for (HandlerAdapter ha : this.handlerAdapters) {	
			//适配器调用supports方法,判断当前处理器是否和适配器匹配
			if (ha.supports(handler)) {
				return ha;
			}
		}
	}
}

HandlerAdapter 处理器适配器

/**
 * 映射器适配器,我们常用到的实现类有RequestMappingHandlerAdapter......
 * 因SpringMVC中的Handler可以有多种实现方式,但是Servlet需要的处理方法的结构确实固定的,
 * 都是以为Request和Response作为入参,那么如何让固定参数中的Servlet处理方法调用灵活的Handler来处理呢,这就是需要Handler来作适配。
 */ 
public interface HandlerAdapter {
	//传入处理器,判断当前处理器适配器是否匹配
	//初始化DispatcherServlet的时候会创建所有的处理器适配器,会有多个处理器适配器。
	//会挨个遍历调用supports查询处理器方法和哪个处理器适配器适配。
	//他是怎么查询的呢,前面我们提到过不同的处理器映射器所对应的适配器类型不同
	//RequestMappingHanlderMapping处理器类是HandlerMethod,
	//BeanNameUrlHandlerMapping处理器实现类是HttpRequestHandler,底层是根据这个类型进行判断的。
	boolean supports(Object handler);
}

AbstractHandlerMethodAdapter

/**
 * 针对@ReqeustMapping注解的处理器适配器
 */
public abstract class AbstractHandlerMethodAdapter{
	//根据传入的处理器,判断当前适配器是否适配该处理器,HandlerMethodAdapter
	public final boolean supports(Object handler) {
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}
}

RequestMappingHandlerAdapter

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter{
	protected boolean supportsInternal(HandlerMethod handlerMethod) {
		return true;
	}
}

控制器处理器初始化

在这里插入图片描述
总结:

  1. 底层使用了适配器模式。
  2. 每个处理器都有自己适合的处理器适配器。
  3. 在SpringMVC当中处理器适配器也有很多种,其中一个比较有名的处理器适配器是:RequestMappingHandlerAdapter
    这个处理器是适配器是专门处理处理器方法上有 @RequestMapping 注解的。
  4. HandlerAdapter也是一个接口,其中一个比较常用的实现类:RequestHandlerAdapter。
  5. 在服务器启动阶段,所有的HandlerAdapter接口实现类都会创建出来,放在DispatcherServlet 类的List<HandlerAdapter> handlerAdapters 中。
  6. HandlerAdapter接口非常重要,通过他来调用最终的HandlerMethod
  7. HandlerAdapter是适配器,是对HandlerMethod进行的适配。

六、SpringMVC拦截器执行源码解读

DispatcherServlet

//前端控制器,SpringMVC最核心的类部分代码
public class DispatcherServlet extends FrameworkServlet {
	protected void doDispatch(HttpServletRequest processedRequest, HttpServletResponse response){
		//执行该请求对应的所有拦截器的preHandler方法
		if (!mappedHandler.applyPreHandle(processedRequest, response)) {
			return;
		}
		//执行该请求所有拦截器中的postHandle方法
		mappedHandler.applyPostHandle(processedRequest, response, mv);
		//执行该请求所有拦截器中的afterCompletion方法
		mappedHandler.triggerAfterCompletion(request, response, null);
	}
}

HandlerExecutionChain

/**
 * 处理器执行链对象
 */
public class HandlerExecutionChain {
	//本次请求所有要执行的拦截器
	private List<HandlerInterceptor> interceptorList;
	//本次请求所有要执行的拦截器 数组格式,和interceptorList是一样的
	private HandlerInterceptor[] interceptors;
	//最后执行的拦截器下标
	private int interceptorIndex = -1;
	
	//执行处理器执行链中所有拦截器的preHandle方法
	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					//如果拦截器拦截了,直接执行afterCompletion方法
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}
	
	//执行处理器执行链中所有拦截器的postHandle方法
	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			//postHandle是根据拦截器配置的反序执行
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}
	
	//执行处理器执行链中所有拦截器的afterCompletion方法
	void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
			throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			//interceptorIndex此时值是最大下标,所以afterCompletion也是反序执行的
			for (int i = this.interceptorIndex; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.afterCompletion(request, response, this.handler, ex);				
			}
		}
	}
	
	//获取处理器执行链中的所有拦截器,返回的是一个数组
	public HandlerInterceptor[] getInterceptors() {
		if (this.interceptors == null && this.interceptorList != null) {
			this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
		}
		return this.interceptors;
	}

}

总结:

  1. DispatcherServlet根据请求获取处理器执行链,里面封装了本次请求所要执行的所有拦截器。
  2. 拦截器的preHandle方法是按照拦截器的顺序依次执行的,当有一个拦截器的返回值是false时,会根据interceptorIndex倒序执行所有拦截器的afterCompletion方法,执行完成后,程序结束运行。
  3. 当拦截器所有的preHandle方法都是返回true时,才会执行postHandle方法,拦截器的postHandle方法执行顺序是倒序的。
  4. 拦截器的afterCompletion方法是在将视图响应给前端前执行,或者在preHandle方法返回false的时候执行的。会根据执行拦截器最大索引interceptorIndex倒序执行

七、处理器适配器执行方法原理

适配器执行方法代码ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

HandlerAdapter 处理器适配器

public interface HandlerAdapter {
	//处理器是配置执行方法,返回一个ModelAndView对象
	//前面我们说到,springMVC有多种处理器适配器,每个处理器适配器都会实现这个方法,
	//作为SpringMVC角度来看,SpringMVC不关心怎么实现的,只要保证根据请求Request和Response作为入参,返回执行结果并且封装成ModelAndView	
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}

ModelAndView

public class ModelAndView {
	//视图对象,里面包含了要跳转的视图地址信息
	private Object view;
	//实质是一个Map,用于存取数据,
	private ModelMap model;
}

AbstractHandlerMethodAdapter 处理器适配器抽象类

//这个处理器适配器匹配的是@RequestMapping注解写的方法
public abstract class AbstractHandlerMethodAdapter implements HandlerAdapter{

	//执行处理器方法,
	@Override
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler){
		return handleInternal(request, response, (HandlerMethod) handler);
	}

	//抽象方法,子类RequestMappingHandlerAdapter重写了该方法
	protected abstract ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod);}
}

RequestMappingHandlerAdapter 针对注解方式实现处理器的适配器

//AbstractHandlerMethodAdapter的子类,这个处理器是专门处理器注解方式实现的处理器
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter{
	
	@Override
	protected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) {
		ModelAndView mav;
		//执行处理器方法
		return mav = invokeHandlerMethod(request, response, handlerMethod);
	}

	protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
			//ServletInvocableHandlerMethod底层继承了HandlerMethod
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			//执行方法
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			//封装成ModelAndView对象
			return getModelAndView(mavContainer, modelFactory, webRequest);
	}
}

ServletInvocableHandlerMethod 底层继承了HandlerMethod

//底层是继承了HandlerMethod
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod{

	public void invokeAndHandle(ServletWebRequest webRequest,ModelAndViewContainer mavContainer, Object... providedArgs) {
		invokeForRequest(webRequest, mavContainer, providedArgs);
	}
	//执行方法
	protected Object doInvoke(Object... args) throws Exception {
		return getBridgedMethod().invoke(getBean(), args);
	}
}

InvocableHandlerMethod

public class InvocableHandlerMethod extends HandlerMethod {
	
	//参数解析器对象,实质是一个List<HandlerMethodArgumentResolver>集合
	private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite();
	
	public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) {
		//获取执行方法的请求参数
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		//执行方法
		Object returnValue = doInvoke(args);
		//返回执行结果
		return returnValue;
	}
	
	//获取执行方法的参数
	private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
				Object... providedArgs) throws Exception {
		//获取该方法的所有形参
		MethodParameter[] parameters = getMethodParameters();
		Object[] args = new Object[parameters.length];
		//遍历所有的形参,并且去根据形参名请求request里取值
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			//使用参数解析器解析参数值
			args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
		}
		return args;
	}
	
}

HandlerMethod处理器方法对象

public class HandlerMethod {
	//执行方法所有的类字节码
	private final Class<?> beanType;
	
	//实际要执行的方法
	private final Method bridgedMethod;
	
	//处理器方法所有请求参数信息,SpringMVC初始化的时候这里会将这个处理器的参数封装到这里
	private final MethodParameter[] parameters;

	public MethodParameter[] getMethodParameters() {
		return this.parameters;
	}
	
	protected Method getBridgedMethod() {
		return this.bridgedMethod;
	}
}

HandlerMethodArgumentResolverComposite 处理器参数解析器

//这个对象是解析器增强对象,里面有真正的解析器集合
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
	
	//真正的参数解析器,根据处理器的实现的方式不同,会有多个参数解析器
	private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<HandlerMethodArgumentResolver>();
	
	
	//解析参数
	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		//根据请求匹配对应的参数解析器
		HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
		//参数解析器解析参数值
		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
	}
	
	
	//根据请求匹配对应的参数解析器
	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
		HandlerMethodArgumentResolver result;
		if (result == null) {
			for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
				//这里只针对RequestParamMethodArgumentResolver解析器做源码跟踪
				if (methodArgumentResolver.supportsParameter(parameter)) {
					result = methodArgumentResolver;
					break;
				}
			}
		}
		return result;
	}
}

HandlerMethodArgumentResolver 方法参数解析器接口

/**
 * 处理器方法参数解析器 AbstractNamedValueMethodArgumentResolver是针对注解实现处理器的参数解析器
 */
public interface HandlerMethodArgumentResolver {
	//根据传入参数对象,判断当前解析器是否能够进行解析
	boolean supportsParameter(MethodParameter parameter);
	
	//解析参数
	Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}

AbstractNamedValueMethodArgumentResolver 处理@ReqeustMapping注解方式的参数解析器

//针对@RequestMapping注解实现方式的参数解析器
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
	
	//解析参数
	public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		//获取形参名称
		NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
		MethodParameter nestedParameter = parameter.nestedIfOptional();
		//根据形参名,去请求中获取参数
		Object arg = resolveName(namedValueInfo.name, nestedParameter, webRequest);
	}
	
	//获取形参名,并且封装成为NamedValueInfo格式
	//NamedValueInfo:里面封装了参数名称和值的信息
	private NamedValueInfo getNamedValueInfo(MethodParameter parameter) {
	
		//创建一个形参和值的映射对象,
		//这里会判断处理器上面是否有@RequestParam注解,如果有就从注解上获取value参数名
		NamedValueInfo namedValueInfo = createNamedValueInfo(parameter);
	
		//判断是否从注解中获取到了请求参数名,如果没有获取,就要通过asm去获取形参名
		namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
		return namedValueInfo;
	}
	
	private NamedValueInfo updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info) {
		String name = info.name;
		if (info.name.length() == 0) {
			//通过asm技术去获取形参名
			name = parameter.getParameterName();
		}
		String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue);
		return new NamedValueInfo(name, info.required, defaultValue);
	}
	
	//参数名称和值的封装对象
	protected static class NamedValueInfo {
		//参数名称
		private final String name;
		//参数是否必须
		private final boolean required;
		//默认值
		private final String defaultValue;
		
		public NamedValueInfo(String name, boolean required, String defaultValue) {
			this.name = name;
			this.required = required;
			this.defaultValue = defaultValue;
		}
	}
	
}

RequestParamMethodArgumentResolver 请求参数解析器

/**
 * 这个参数解析器主要处理带有@RequestParam注解的以及一些基本数据类型
 */
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver{
	@Override
	protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
		RequestParam ann = parameter.getParameterAnnotation(RequestParam.class);
		return (ann != null ? new RequestParamNamedValueInfo(ann) : new RequestParamNamedValueInfo());
	}
	
	//从请求中获取参数
	@Override
	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
		Object arg = null;
		if (arg == null) {
			String[] paramValues = request.getParameterValues(name);
			if (paramValues != null) {
				arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
			}
		}
		return arg;
	}
	
	//根据传入方法参数对象,判断当前解析器是否能够进行解析
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		//判断方法请求参数对象是否有@RequestParam注解,如果有说明匹配上了
		if (parameter.hasParameterAnnotation(RequestParam.class)) {
			return true;
		} else {
			
			parameter = parameter.nestedIfOptional();
			//springMVC初始化的时候会初始化两个RequestParamMethodArgumentResolver参数解析器
			//其中有一个useDefaultResolution是true,这样做的目的是为了给用户自定义的HandlerMethodArgumentResolver让出更多的可能性。
			//感兴趣的可以去深入研究
			if (this.useDefaultResolution) {
				//判断参数是否是简单类型,如果是简单类型就返回匹配上了
				return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
			}
			else {
				return false;
			}
		}
	}
}

MethodParameter 处理器方法请求参数对象

public class MethodParameter {
	//参数名称解析器,用来发现方法和构造函数的参数名称的,SpringMVC启动的时候会自动加载进来
	private volatile ParameterNameDiscoverer parameterNameDiscoverer;
	
	public String getParameterName() {
		ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
		if (discoverer != null) {
			String[] parameterNames = discoverer.getParameterNames(this.method);
			if (parameterNames != null) {
				this.parameterName = parameterNames[this.parameterIndex];
			}
		}
		return this.parameterName;
	}
}

ParameterNameDiscoverer 参数名称解析器

/**
 * 参数名称解析器
 */
public interface ParameterNameDiscoverer {

	//根据方法,解析所有的参数名称
	String[] getParameterNames(Method method);
}

PrioritizedParameterNameDiscoverer


public class PrioritizedParameterNameDiscoverer implements ParameterNameDiscoverer {
	//springMVC启动会注册多个参数解析器 其中就包含LocalVariableTableParameterNameDiscoverer
	private final List<ParameterNameDiscoverer> parameterNameDiscoverers = new LinkedList<ParameterNameDiscoverer>();
		
	//根据方法获取方法名称,循环遍历参数解析器,并且进行解析,直到解析到了值
	public String[] getParameterNames(Method method) {
		for (ParameterNameDiscoverer pnd : this.parameterNameDiscoverers) {
			String[] result = pnd.getParameterNames(method);
			if (result != null) {
				return result;
			}
		}
		return null;
	}
}

LocalVariableTableParameterNameDiscoverer 参数解析器

public class LocalVariableTableParameterNameDiscoverer implements ParameterNameDiscoverer {
	//根据请求方法获取方法参数名称
	public String[] getParameterNames(Method method) {
		Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);
		Class<?> declaringClass = originalMethod.getDeclaringClass();
		map = inspectClass(declaringClass);
		return null;
	}
	
	//检析Class,获取方法形参名称
	private Map<Member, String[]> inspectClass(Class<?> clazz) {
		InputStream is = clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz));
		//这里使用了asm,动态获取方法参数名称
		ClassReader classReader = new ClassReader(is);
		Map<Member, String[]> map = new ConcurrentHashMap<Member, String[]>(32);
		classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);
		return map;
	}
}

总结:

  1. 处理器适配器接口有一个方法handle方法,这个方法传入RequestResponse以及处理器去执行处理器方法,并且将返回值封装成ModelAndView对象。
  2. SpringMVC是如何获取请求参数的,其实最本质的方式还是根据@RequestParam注解的value属性获取请求参数名称,然后再从request中获取。
  3. 不带@RequestParam注解的请求参数又是如何获取的呢,SpringMVC底层用的其实是asm框架的方式来获取参数名称,然后再去request中获取。

网站公告

今日签到

点亮在社区的每一天
去签到