先来了解几个属性概念
比如访问这个的时候
@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来进行处理。
- RequestMappingHandlerAdapter主要是适配注解类处理器,注解类处理器就是我们经常使用的@Controller的这类处理器;能解析注解方法的适配器,处理器类中只要有标了注解的这些方法就能用。
- HttpRequestHandlerAdapter主要是适配静态资源处理器,静态资源处理器就是实现了HttpRequestHandler接口的处理器,这类处理器的作用是处理通过SpringMVC来访问的静态资源的请求。
- 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;
}
}