SpringMvc源码分析

309 阅读5分钟

SpringMvc源码分析

一、Mvc模式解读

Model1 模型

image.png

jspjavaBean两部分组成,jsp既要展示数据又要处理数据(也就是同时干了控制器和视图的事情)

Model2

image.png 它是mvc模型的一个经典应用,处理请求和展示数据进行分离,提高了代码的可重复性与易维护性

二、SpringMvc执行流程图解

1、 用户发送请求至前端控制器DispatcherServlet。

2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、 DispatcherServlet调用HandlerAdapter处理器适配器。

5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、 Controller执行完成返回ModelAndView。

7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、 ViewReslover解析后返回具体View。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、 DispatcherServlet响应用户。

image.png

三、底层源码剖析

1.doService()

//精简版-代码不全,只为方便理解流程	
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  
		try {
			doDispatch(request, response);
		}
		finally {
      //……
		}
	}

2.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 {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

			  // 获得处理器执行链对象HandlerExecutionChain mappedHandler
				mappedHandler = getHandler(processedRequest);

				// 通过处理器获取对应的处理器适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// 适配器调用控制器中的方法,返回ModelAndView对象.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				//应用默认的视图名字
				applyDefaultViewName(processedRequest, mv);
        //应用相应的拦截器的方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				//……
			}
      //进行结果的解析
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		finally {
	  //……
		}
	}

3.getHandler()

	//获得处理器执行链对象(包含处理器和拦截器)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
      //遍历HandlerMapping处理器映射器的list集合,拿到对应的对象
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

4.getHandlerAdapter()

	//获取处理器适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
      //遍历处理器适配器的list集合,找到对应的适配器
			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");
	}

5.handle()

//HandlerAdapter.handle() 接口
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
//AbstractHandlerMethodAdapter.handle() 抽象类
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return handleInternal(request, response, (HandlerMethod) handler);
	}
//RequestMappingHandlerAdapter.handleInternal() 具体的实现——注解一般使用这个适配器
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;
	}

6.processDispatchResult()

	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		if (mv != null && !mv.wasCleared()) {
      //渲染结果
			render(mv, request, response);
		}
	}

7.render()

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {

		View view;
		String viewName = mv.getViewName(); //获取view视图名字
		if (viewName != null) {
			// 视图解析,返回具体的view对象
			view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
			}
		else {
			view = mv.getView();
		}
		try {
      //mv.getModelInternal()其实就是model数据
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			throw ex;
		}
	}

四、控制器不同实现方式与底层源码剖析

1.方式一:实现Controller接口

public class Test01 implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        System.out.println("Controller接口 ..............");
        return null;
    }
}

2.方式二:实现HttpRequestHandler接口

public class Test02 implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
        System.out.println("HttpRequestHandler.........");
    }
}

3.方式三:使用@Controller注解

@Controller
public class Test03 {
    @RequestMapping("/test03")
    public void  test03(){
        System.out.println("Controller注解 ......");
    }
}

三种不同的实现方式,对应不同的处理器与适配器,因此的handle方法也会有区别

五、参数注入解密

	protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
		HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
		Object arg = null;
		
		if (arg == null) {
      //开始获取参数
			String[] paramValues = request.getParameterValues(name);
			if (paramValues != null) {
				arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
			}
		}
		return arg;
	}

① 通过注解进行绑定 @RequestParam

② 通过参数名称进行绑定. 使用注解进行绑定,我们只要在方法参数前面声明@RequestParam("a"),就可以将request中参数a的值绑定到方法的该参数上。使用参数名称进行绑定的前提是必须要获取方法中参数的名称,Java反射只提供了获取方法的参数的类型,并没有提供获取参数名称的方法。SpringMVC解决这个问题的方法是用asm框架读取字节码文件,来获取方法的参数名称。

六、Spring与Springmvc容器关系

spring是一个一站式的轻量级的java开发框架,核心是控制反转(IOC)和面向切面(AOP),针对于开发的WEB层(springMvc)、业务层(Ioc)、持久层(jdbcTemplate)等都提供了多种配置解决方案;

springMvc是spring基础之上的一个MVC框架,主要处理web开发的路径映射和视图渲染,属于spring框架中WEB层开发的一部分;

父子容器

image.png 子容器(SpringMVC容器)可以访问父容器(Spring容器)的Bean,父容器(Spring容器)不能访问子容器(SpringMVC容器)的Bean。也就是说,当在SpringMVC容器中getBean时,如果在自己的容器中找不到对应的bean,则会去父容器中去找,这也解释了为什么由SpringMVC容器创建的Controller可以获取到Spring容器创建的Service组件的原因