Spring MVC流程简单说明

先来了解几个属性概念

比如访问这个的时候

@RequestMapping("/hello")
	public String hello(){
		String hello = helloService.sayHello("tomcat..");
		return hello;
}

@RequestMapping("/suc")
	public String success(){
		System.out.println("运行了success()");
		return "success";
}

HandlerMethod

我们的请求的方法,都被封装成HandlerMethod。

public class HandlerMethod {
 
    // 虽然Object类型,但是注册handlerMethod时候构造的时候有可能传入的是一个String类型的bean name
	private final Object bean;
 
    // 见名知义,我调试的时候,传入的是DefaultListableBeanFactory,如果bean属性是Sring的beanName就可以用beanName获取到对应的bean作用Handler
	private final BeanFactory beanFactory;
 
    // 方法所属类
	private final Class<?> beanType;
 
    // 注册的方法
	private final Method method;
 
    // 被桥接的方法,如果method是原生的,这个属性的值就是method
	private final Method bridgedMethod;
 
    // 封装方法参数的类实例,一个MethodParameter就是一个参数
	private final MethodParameter[] parameters;
 
    // Http状态码
	private HttpStatus responseStatus;
 
    // ResponseStatus注解的reason值
	private String responseStatusReason;

}

HandlerAdapter

当handlerMapping获取到执行请求的controller时,DispatcherServlte会根据controller对应的controller类型来调用相应的HandlerAdapter来进行处理。

  1.  RequestMappingHandlerAdapter主要是适配注解类处理器,注解类处理器就是我们经常使用的@Controller的这类处理器;能解析注解方法的适配器,处理器类中只要有标了注解的这些方法就能用。
  2. HttpRequestHandlerAdapter主要是适配静态资源处理器,静态资源处理器就是实现了HttpRequestHandler接口的处理器,这类处理器的作用是处理通过SpringMVC来访问的静态资源的请求。        
  3. SimpleControllerHandlerAdapter是Controller处理适配器,适配实现了Controller接口或Controller接口子类的处理器,比如我们经常自己写的Controller来继承MultiActionController. 

HandlerMapping

处理@RequestMapping 注解,并将其注册到请求映射表中,保存在AbstractHandlerMethodMapping的mappingLookup属性中;
下一次请求过来,就来看哪个HandlerMapping中有这个请求映射信息就行了;|

用来映射url和对应的处理类,RequestMappingHandlerMapping是一个实现类,用注解就是使用它。

 RequestMappingHandlerMapping是继承AbstractHandlerMethodMapping,所以有mappingLookup属性,这个是拿来放rul对应的方法

SimpleUrlHandlerMapping:将请求直接交给tomcat ;有他,静态资源就没问题;

HandlerExecutionChain

HandlerExecutionChain是Handler执行链,有以下三个属性,用来执行拦截器的方法和执行Controller类的url映射的方法

private final Object handler;  //url所映射的方法。
private HandlerInterceptor[] interceptors; //拦截器数组
private List<HandlerInterceptor> interceptorList; //拦截器列表

 下图可以看出Object handler 确实是hello()方法

开始

请求进来,在doDispatch打个断点看栈,由下图看出大概过程 

由原生servlet.service -----> FrameworkServlet.doGet -----> DispatcherServlet.doService -----> DispatcherServlet.doDispatch

 

参考:SpringMVC(关于HandlerMapping执行流程原理分析)

 

主要的部分doDispatch作了大部分操作

//忽略不重要部分
protected void doDispatch(HttpServletRequest request, HttpServletResponse response){
    HandlerExecutionChain mappedHandler;
    //获取执行链
    mappedHandler = getHandler(processedRequest);

    //拿到能执行我们请求的方法的适配器,看文章,有简易实现mvc适配器的例子    https://blog.csdn.net/a362212624/article/details/80431499
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

    // 拦截器的preHandle()方法就是在这里被调用的
    // 可见,如果preHandle()方法返回false,则终止分发流程,直接返回
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
         return;
    }

    // 这一行是对我们写的Controller方法的真正调用,mappedHandler.getHandler()就是我们那个方法
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    // 拦截器的postHandle()方法就是在这里被调用的,即在Controller调用完成之后
    mappedHandler.applyPostHandle(processedRequest, response, mv);


    //处理视图并跳转到页面
    //根据方法最终执行完成后封装的ModelAndView;转发到对应页面,而且ModelAndVi ew中的数据可以从请求域中获取
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

}

 

1.mappedHandler = getHandler(processedRequest)的大概源码

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		for (HandlerMapping hm : this.handlerMappings) {
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}

上面的代码获取HandlerExecutionChain ,是由下面这一段执行的

HandlerMapping的引用是RequestMappingHandlerMapping

hm.getHandler(request)调用RequestMappingHandlerMapping父类AbstractHandlerMapping的getHandler()

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 根据请求获取执行程序,具体的获取方式由子类决定,getHandlerInternal() 是抽象方法
    Object handler = getHandlerInternal(request);
    
    // 将 Handler 与一堆拦截器包装到 HandlerExecutionChain 对象中
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    return executionChain;
}

 

2.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler())的大概源码

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

 mappedHandler.getHandler()就是开头提的HandlerMethod类,里面getHandlerAdapter需要的信息

判断方法进入到RequestMappingHandlerAdapter的子类AbstractHandlerMethodAdapter的supports:

handler判断是否是HandlerMethod 的类,或者其子类、实现类的实例 ,看源码supportsInternal((HandlerMethod) handler)永远为true。

	public final boolean supports(Object handler) {
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}

 

3.mv = ha.handle(processedRequest, response, mappedHandler.getHandler())执行的是AbstractHandlerMethodAdapter的handle

而handle有执行了个模板方法handleInternal,由子类RequestMappingHandlerAdapter实现

AbstractHandlerMethodAdapter:

	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
		return handleInternal(request, response, (HandlerMethod) handler);
	}

RequestMappingHandlerAdapter: 

protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		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 {
			// 不需要同步会话就执行这块,我的案例请求就是请求这个,这个就是运行success方法();
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		return mav;
	}

然后在一层层进入,最后到InvocableHandlerMethod 类使用反射执行方法,getBridgedMethod就是请求的方法,getBean就是请求的方法的所在类(controller),可以看上面HandlerMethod 结构说明。

public class InvocableHandlerMethod extends HandlerMethod {
    protected Object doInvoke(Object... args) throws Exception {
        return getBridgedMethod().invoke(getBean(), args);
    }
}	

下面是方法参数获取和设置的过程 

public class InvocableHandlerMethod extends HandlerMethod{
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      Object... providedArgs){
......

//设置参数值

args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
......

}

经过好几步最后来到这个类方法

public class AbstractNamedValueMethodArgumentResolver{
//获得参数名
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
Object resolvedName = resolveStringValue(namedValueInfo.name);

//获得参数值
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
}

上面的resolveName(resolvedName.toString(), nestedParameter, webRequest);来到这个 ,也看出获取参数值也是用的request.getParameterValues(name);然后赋值。

public class RequestParamMethodArgumentResolver{

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值