前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何从源码角度看SpringMVC执行过程?

如何从源码角度看SpringMVC执行过程?

作者头像
Java深度编程
发布2021-11-30 15:35:40
5000
发布2021-11-30 15:35:40
举报
文章被收录于专栏:Java深度编程Java深度编程

springMVC有两种注册web接口的方式:

一:使用@ResquestMapper

注册

二:继承Controller接口, 使用 @Component注册Bean

不同的注册方式有不同的handle处理!!!

方式一:使用Controller接口:

编写方式:

创建自定义类,继承Controller接口,重写handleRequest方法。使用@Component(”xxx")注入映射路径。

代码语言:javascript
复制
@Component("/test")
public class TestControllerI implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("执行Controller接口自定义实现类TestControllerI了!!!");
        return null;
    }
}

执行逻辑:

1.首先执行DispatchServlet中的doDispatch方法,

2.getHandler() 获取 handler对象,先匹配到BeanNameHandlerMapping,再调用 getHandler(request),得到手写的集成Controller的api接口类handler对象。

3.getHandlerAdapter() 获取 adapter对象;

4. adapter对象调用 mv = ha.handle(processedRequest,response, mappedHandler.getHandler())

会执行到 SimpleControllerHandlerAdapter类中的handle(),通过强制装换成Controller接口对象,实际上就是我们写的实现Controller接口的对象,调用handleRequest()就调用了自己重写的方法。

核心代码如下:

DispatcherServlet 的doService()方法的核心代码:

代码语言:javascript
复制
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
   noHandlerFound(processedRequest, response);
   return;
}

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

……

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

如上代码,先通过request信息匹配获取对应的handle处理器(不同注册方式有不同的handle),然后通过handle匹配获取对应的Adapter,最后再通过Adapter对象调用handle方法,完成真实方法的调用。

代码语言:javascript
复制
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) {
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}
代码语言:javascript
复制
public class SimpleControllerHandlerAdapter implements HandlerAdapter {

   @Override
   @Nullable
   public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
         throws Exception {

      return ((Controller) handler).handleRequest(request, response);
   }
  …………
}

此处的核心代码((Controller) handler).handleRequest(request, response),这个强转就是转成我们自定义的实现Controller接口的实现类对象,调用handleRequest方法就进入到我们写的真实方法里了。

方式二:使用@RequestMapping

编写方式:

自定义类打上@Controller注解托管,使用@RequestMapping("xxx")注入映射路径。

代码语言:javascript
复制
@Controller
@RequestMapping("/test/a)
public class TestA {

    @GetMapping("/get")
    public ModelAndView getMyProcessApplyList() {
       System.out.println("注解方式");
       return null;
    }
}

执行逻辑:

逻辑与方式一获取Handle逻辑一样,只不过先匹配到的mapping对象不是BeanNameHandlerMapping而是RequestMappingHandlerMapping,通过RequestMappingHandlerMapping对象,调用mapping.getHandler(request),得到的Handler对象是HandlerMethod handlerMethod,也就是我们写的方法对象的包装类。

获取的handle不同,执行ha.handle过程就不一样,接口方式进入的是 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter

注解 方式进入的是

org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter

代码语言:javascript
复制
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {

   return handleInternal(request, response, (HandlerMethod) handler);
}

如上,进一步调用handleInternal方法,将执行到

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

代码语言:javascript
复制
@Override
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) {
    ……
   }
   else {
      // No synchronization on session demanded at all...
      mav = invokeHandlerMethod(request, response, handlerMethod);
   }

   ……

   return mav;
}

注意上面的核心代码 invokeHandlerMethod(request, response, handlerMethod),该方法就是调用真实方法的入口。

代码语言:javascript
复制
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      …………

    invocableMethod.invokeAndHandle(webRequest, mavContainer);
    if (asyncManager.isConcurrentHandlingStarted()) {
       return null;
    }
      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}

注意上面invocableMethod.invokeAndHandle(webRequest, mavContainer) 这一行就是调用真实方法的更深一步入口。

咋们继续再往下看invokeAndHandle方法

代码语言:javascript
复制
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {

   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
   setResponseStatus(webRequest);

   if (returnValue == null) {
      if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
         disableContentCachingIfNecessary(webRequest);
         mavContainer.setRequestHandled(true);
         return;
      }
   }
   else if (StringUtils.hasText(getResponseStatusReason())) {
      mavContainer.setRequestHandled(true);
      return;
   }

   mavContainer.setRequestHandled(false);
   Assert.state(this.returnValueHandlers != null, "No return value handlers");
   try {
      this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
   }
   catch (Exception ex) {
      if (logger.isTraceEnabled()) {
         logger.trace(formatErrorForReturnValue(returnValue), ex);
      }
      throw ex;
   }
}

invokeForRequest()方法:

代码语言:javascript
复制
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {

   Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
   if (logger.isTraceEnabled()) {
      logger.trace("Arguments: " + Arrays.toString(args));
   }
   return doInvoke(args);
}

这里有一行关键的代码,就是doInvoke(args),代码如下:

代码语言:javascript
复制
    protected Object doInvoke(Object... args) throws Exception {
      ReflectionUtils.makeAccessible(getBridgedMethod());
      try {
         return getBridgedMethod().invoke(getBean(), args);
      }
      ……
   }

我们进入getBridgedMethod()方法,会发现获取的正是我们再controller层写的方法对象。

那么拿到了Method方法对象,再调用invoke方法,这不就是我们熟知的反射api吗!所以最终就是通过这里的反射调用了我们的真实方法。

看到这里同学们应该明白了springMVC执行方法的过程,真实方法执行以后,接下来就是视图解析,咋们下期再见!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-11-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java深度编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档