通过网盘分享的文件:SpringMVC6
链接: https://pan.baidu.com/s/1zXHQejjbU-hD3bMyBaGVJw?pwd=648t 提取码: 648t
–来自百度网盘超级会员v6的分享

十三、源码分析

1、源码分析SpringMVC执行流程

// 前端控制器,SpringMVC最核心的类
public class DispatcherServlet extends FrameworkServlet {
	// 前端控制器最核心的方法,这个方法是负责处理请求的,一次请求调用一次doDispatch 方法
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 1、通过请求获取处理器
		// 请求:http://localhost:8080/springmvc/hello (有URI)
		// 根据请求路径来获取对应的要执行的处理器
		// 实际上返回的是一个处理器执行链对象
		// 这个执行链(链条)把这一次请求要执行的所有拦截器和处理器串起来了
		// HandlerExecutionChain是一次请求对应一个对象
		HandlerExecutionChain mappedHandler = getHandler(processedRequest);
		
		// 2、根据处理器获取处理器适配器对象
		// Handler就是我们写的Controller
		HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

		// 3、执行该请求对应的所有拦截器中的 preHandle 方法
		if (!mappedHandler.applyPreHandle(processedRequest, response)) {
			return;
		}
		// 4、调用处理器方法返回ModelAndView对象
		// 在这里进行的数据绑定,实际上调用处理器方法之前要给处理器方法传参
		// 需要传参的话,这个参数实际上是要经过一个复杂的数据绑定过程(将前端提交的表单数据转换成POJO对象)
		mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

		// 5、执行该请求对应的所有拦截器中的 postHandle 方法
		mappedHandler.applyPostHandle(processedRequest, response, mv);

		// 6、处理分发结果(本质上就是响应结果到浏览器)
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}

	/**
	* 处理分发结果
	*/
	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {
		// 7、渲染
		render(mv, request, response);
		// 11、执行该请求所对应的所有拦截器的afterCompletion方法
		mappedHandler.triggerAfterCompletion(request, response, null);
	}

	/**
	* 渲染
	*/
	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 8、通过视图解析器进行解析,返回视图View对象
		View view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
		// 10、调用视图对象的渲染方法(完成响应)
		view.render(mv.getModelInternal(), request, response);
	}

	/**
	* 渲染
	*/
	protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {
		// 视图解析器
		ViewResolver viewResolver;
		// 9、通过视图解析器解析返回视图对象View
		View view = viewResolver.resolveViewName(viewName, locale);
	}
}


// 视图解析器接口
// 视图解析器接口实现类也很多:ThymeleafViewResolver、InternalResourceViewResolver
public interface ViewResolver {
	View resolveViewName(String viewName, Locale locale) throws Exception;
}



// 视图接口
// 每一个接口肯定是有接口下的实现类,例如View接口的实现类:ThymeleafView、InternalResourceView....
public interface View{
	void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception;
}

2、分步源码分析

(1)、根据请求获取处理器执行链

  1. 分析这一行代码

    HandlerExecutionChain mappedHandler = getHandler(request);
    

    HandlerExecutionChain是处理器执行链对象

  2. HandlerExecutionChain中的属性

    public class HandlerExecutionChain{
    	// 底层对应的是一个HandlerMethod对象
    	// 处理器方法对象
    	Object handler = new HandlerMethod(.....);
    	// 该请求对应的所有的拦截器按照顺序放到了ArrayList集合中
    	// 所有的拦截器对象也都是在服务器启动的时候都创建好
    	List<HandlerInterceptor> interceptorList;
    }
    
  3. HandlerMethod 是什么

    HandlerMethod是最核心的要执行的目标,翻译为:处理器方法
    注意:HandlerMethod 是在web服务器启动时初始化spring容器的时候就创建好了
    这个类当中比较重要的属性包括:beanName和Method
    例如以下代码

    @Controller("userController")
    public class UserController{
    	@RequestMapping("/login")
    	public String login(User user){
    		return ....
    	}
    }
    

    那么以上代码对应了一个HandlerMethod对象

    public class HandlerMethod{
    	private String beanName = "userController";
    	private Method loginMethod;
    }
    
  4. getHandler(request);
    这个方法还是在DispatcherServlet类中

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    	if (this.handlerMappings != null) {
    		for (HandlerMapping mapping : this.handlerMappings) {
    			// 通过合适的 HandlerMapping才能获取到 HandlerExecutionChain对象
    			// 如果处理器方法使用了 @RequestMapping注解,那么以下代码中的mapping是:RequestMappingHandlerMapping对象
    			HandlerExecutionChain handler = mapping.getHandler(request);
    			if (handler != null) {
    				return handler;
    			}
    		}
    	}
    	return null;
    }
    

    重点

    • 处理请求的第一步代码是:HandlerExecutionChain mappedHandler = getHandler(request);

      其本质上是调用了:HandlerExecutionChain handler = mapping.getHandler(request);

      mapping变量就是 HandlerMapping

    • HandlerMapping是一个接口,翻译为处理器映射器,专门负责映射的,就是本质上根据请求路径去映射处理器方法的

    • HandlerMapping接口下有很多实现类

      例如其中一个比较常用的:RequestMappingHandlerMapping

      这个RequestMappingHandlerMapping 叫做:@RequestMapping注解专用的处理器映射器对象

      如果没有使用 @RequestMapping注解,也可以写xml配置文件来进行映射,那个时候对应的就是其他的HandlerMapping接口的实现类了

    • HandlerMapping 对象也是在服务器启动阶段创建的,所有的HandlerMapping对象都是在服务器启动阶段创建,并且存放到集合中

      public class DispatcherServlet{
      	List<HandlerMapping> handlerMappings;
      }
      
  5. RequestMappingHandlerMapping中的 getHandler(request);

    HandlerExecutionChain handler = mapping.getHandler(request);

    mapping.getHandler(request);这个方法底层一定是获取了 HandlerMethod 对象,将其赋值给 HandlerExecutionChain的handler属性

    public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping{
    	protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
    		super.registerHandlerMethod(handler, method, mapping);
    		updateConsumesCondition(mapping, method);
    	}
    }
    
    public class AbstractHandlerMethodMapping{
    	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    		this.mappingRegistry.register(mapping, handler, method);
    	}
    
        public void register(T mapping, Object handler, Method method) {
            HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        }
    
    	protected HandlerMethod createHandlerMethod(Object handler, Method method) {
            if (handler instanceof String beanName) {
                return new HandlerMethod(beanName,
                        obtainApplicationContext().getAutowireCapableBeanFactory(),
                        obtainApplicationContext(),
                        method);
            }
            return new HandlerMethod(handler, method);
    	}
    
    }
    
  6. 这一步涉及的类

    • HandlerExecutionChain

    • HandlerMethod

    • HandlerInterceptor

    • HandlerMapping

      RequestMappingHandlerMapping(是HandlerMaping接口的实现)

(2)、根据处理器来获取处理器适配器

分析:
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

  1. 底层使用了适配器模式

  2. 每一个处理器(自己写的Controller)都有自己适合的处理器适配器

  3. 在SpringMVC当中处理器适配器也有很多种,其中一个比较常用的处理器适配器是:RequestMappingHandlerAdapter
    这个处理器适配器是专门处理 "处理器方法"上有 @RequestMapping 注解的

  4. mappedHandler.getHandler() 获取的是 HandlerMethod 对象

  5. HandlerAdapter也是一个接口,其中有一个常用的实现类:RequestMappingHandlerAdapter

  6. 在服务器启动阶段所有的 HandlerAdapter接口的实现类都会创建出来,在服务器启动阶段!!!!!!
    List handlerAdapters;

  7. HandlerAdapter接口非常重要,通过这个接口来调用最终的 HandlerMethod

  8. HandlerAdapter是适配器,是对 HandlerMethod 进行的适配

  9. 在DispatcherServlet类中,如下代码:

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    	if (this.handlerAdapters != null) {
    		for (HandlerAdapter adapter : this.handlerAdapters) {
    			if (adapter.supports(handler)) {
    				return adapter;
    			}
    		}
    	}
    }
    

(3)、执行拦截器的preHandle

关于执行请求对应的拦截器的preHandle方法

  • DispatcherServlet

    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    	return;
    }
    
  • HandlerExecutionChain

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	for (int i = 0; i < this.interceptorList.size(); i++) {
    		HandlerInterceptor interceptor = this.interceptorList.get(i);
    		if (!interceptor.preHandle(request, response, this.handler)) {
    			triggerAfterCompletion(request, response, null);
    			return false;
    		}
    		this.interceptorIndex = i;
    	}
    	return true;
    }
    

    遍历List集合,从List集合中取出每一个 HandlerInterceptor对象,调用 preHandle,i++可见是顺序调用

(4)、调用处理器方法

关于调用处理器方法

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

这个方法是最核心的,调用请求路径对应的HandlerMethod(调用处理器方法)

  • mv 是ModelAndView对象

  • ha 是处理器适配器

    ha是HandlerAdapter,如果是 @RequestMapping 注解对应的,那么就是 RequestMappingHandlerAdapter

    RequestMappingHandlerAdapter.java

    protected ModelAndView handleInternal(HttpServletRequest request,
    	HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    	mav = invokeHandlerMethod(request, response, handlerMethod);
    }
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
    			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    	// 获取一个数据绑定工厂
    	WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    	// 获取一个可调用的处理器方法
    	ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
    	// 给可调用的方法绑定数据
    	invocableMethod.setDataBinderFactory(binderFactory);
    	// 给可调用的方法设置参数
    	invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    	// 可调用的方法执行了
    	invocableMethod.invokeAndHandle(webRequest, mavContainer);
    }
    

在HandlerAdapter中做的核心事情

  • 将前端提交的form数据通过 HttpMessageConverter 将其转换成 POJO对象(数据转换)
  • 并将数据绑定到 HandlerMethod 对象上
  • 调用HandlerMethod
  • 返回 ModelAndView

(5)、执行拦截器的postHandle

分析DispatcherServlet类中的mappedHandler.applyPostHandle(processedRequest, response, mv);这行代码

实际上调用的是HandlerExecutionChain类中的以下方法

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
			throws Exception {
	for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
		HandlerInterceptor interceptor = this.interceptorList.get(i);
		interceptor.postHandle(request, response, this.handler, mv);
	}
}

通过源码可以很轻松的看到从List集合中逆序(i–)逐一取出拦截器对象并且调用拦截器的 postHandle方法

(6)、处理分发结果

分析这行代码

public class DispatcherServlet{
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 处理分发结果
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
}

执行过程链

public class DispatcherServlet{

	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 1、处理分发结果
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
	// 2、
	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {
		// 3、渲染
		render(mv, request, response);
	}

	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 4、通过视图解析器进行解析,返回视图View对象
		View view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
		// 7、调用视图对象的渲染方法(完成响应)
		view.render(mv.getModelInternal(), request, response);
	}

	// 5、
	protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {
		// 视图解析器
		ViewResolver viewResolver;
		// 6、通过视图解析器解析返回视图对象View
		View view = viewResolver.resolveViewName(viewName, locale);
	}
}


// 视图解析器接口
// 视图解析器接口实现类也很多:ThymeleafViewResolver、InternalResourceViewResolver
public interface ViewResolver {
	View resolveViewName(String viewName, Locale locale) throws Exception;
}


// 视图接口
// 每一个接口肯定是有接口下的实现类,例如View接口的实现类:ThymeleafView、InternalResourceView....
public interface View{
	void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception;
}

(7)、执行拦截器的afterCompletion方法

  • DispatcherServlet

    在分发结果方法中有这行代码mappedHandler.triggerAfterCompletion(request, response, null);

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
    		@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
    		@Nullable Exception exception) throws Exception {
    	// 渲染
    	render(mv, request, response);
    	// 执行该请求所对应的所有拦截器的afterCompletion方法
    	mappedHandler.triggerAfterCompletion(request, response, null);
    }
    
  • HandlerExecutionChain

    实际上调用的是HandlerExecutionChain类中的triggerAfterCompletion方法来调用拦截器的afterCompletion()方法

    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
    	for (int i = this.interceptorIndex; i >= 0; i--) {
    		HandlerInterceptor interceptor = this.interceptorList.get(i);
    		try {
    			interceptor.afterCompletion(request, response, this.handler, ex);
    		}
    		catch (Throwable ex2) {
    			logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
    		}
    	}
    }
    

    通过源码可以看出也是通过逆序(i–)的方式进行拦截器的调用,调用拦截器的afterCompletion方法

3、视图机制源码分析

public class DispatcherServlet extends FrameworkServlet {

	// 前端控制器的核心方法:处理请求、返回视图、渲染视图、都是在这个方法中完成的
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

		
		// 根据请求路径调用映射的处理器方法,处理器方法执行结束之后,返回逻辑视图名称
		// 返回逻辑视图名称之后,DispatcherServlet会将 逻辑视图名称ViewName + Model,将其封装为ModelAndView对象
		mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

		// 这行代码的作用是处理视图
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}

	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {
		// 渲染页面(将模板字符串转换成html代码响应到浏览器)
		render(mv, request, response);
	}

	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 这个方法的作用是将 逻辑视图名称 转换成 物理视图名称 ,并且最终返回视图对象View
		View view = resolveViewName(viewName, mv.getModelInternal(), locale, request);

		// 真正的将模板字符串转换成HTML代码,并且将HTML代码响应给浏览器(真正的渲染)
		view.render(mv.getModelInternal(), request, response);
	}

	protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {
		// 其实这一行代码才是真正起作用的:将 逻辑视图名称 转换成 物理视图名称,并且最终返回视图对象View
		ViewResolver viewResolver;  // 底层会创建一个ThymeleafViewResolver
		// 如果使用的是Thymeleaf,那么返回的视图对象:ThymeleafView对象
		View view = viewResolver.resolveViewName(viewName, locale); 
		return view;
	}

}


// 这是一个接口(负责视图解析的)
public interface ViewResolver { // 如果使用Thymeleaf,那么该接口的实现类就是:ThymeleafViewResolver
	// 这个方法就是将:逻辑视图名称 转换成 物理视图名称,并且最终返回视图对象View
	View resolveViewName(String viewName, Locale locale) throws Exception;
}

// 这是一个接口(负责将 模板字符串 转换成HTML代码,响应给浏览器)
public interface View {
	void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception;
}

/*
	核心类:DispatcherServlet
	核心接口1:ViewResolver(如果你使用的是Thymeleaf,那么底层会创建ThymeleafViewResolver对象)
	核心接口2:View(如果你使用的是Thymeleaf,那么底层会创建ThymeleafView对象)

	结论:如果你自己想实现属于自己的视图至少需要编写两个类
		一个类实现ViewResolver接口,实现其中的resolveViewName方法
		另一个类实现View接口,实现其中的render方法
*/

4、图片角度看执行流程

在这里插入图片描述

5、WEB服务器启动

先搞明白核心类的继承关系
DispatcherServlet extends FrameworkServlet extends HttpServletBean extends HttpServlet extends GenericServlet implements Servlet

服务器启动阶段完成了

  1. 初始化Spring上下文(也就是创建所有的bean,让IoC容器将其管理起来)

  2. 初始化SpringMVC相关的对象:处理器映射器、处理器适配器等

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐