前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring mvc 5.1.1.RELEASE的一次请求过程源码分析

spring mvc 5.1.1.RELEASE的一次请求过程源码分析

作者头像
爬蜥
发布2019-07-09 19:28:27
4100
发布2019-07-09 19:28:27
举报
文章被收录于专栏:爬蜥的学习之旅

从Jetty启动流程可以看到,启动上下文之后,紧接着就开始初始化servlet,调用init方法

代码语言:javascript
复制
 private synchronized void initServlet()
        throws ServletException
    {
        ...
        //调用Servlet的init方法
        _servlet.init(_config);
        ...
    }

从web.xml文件中可以看到,这个servlet就是DispatcherServlet,对应的init方法在父类GenericServlet中

代码语言:javascript
复制
public void init(ServletConfig config) throws ServletException {
//这里servletconfig就被传下来
this.config = config;
//执行子类的init方法
this.init();
}

对应在 HttpServletBean中

代码语言:javascript
复制
public final void init() throws ServletException {
    ...
    initServletBean();
}

在FrameworkServlet中实现对应的spring的servlet的初始化

代码语言:javascript
复制
protected final void initServletBean() throws ServletException {
…
this.webApplicationContext = initWebApplicationContext();
…
}

对应的初始化web容器,首先也会去查询是否已经初始化过了

代码语言:javascript
复制
protected WebApplicationContext initWebApplicationContext() {
    //获取根webapplicationcontext,这就是在IOC容器初始化的时候塞入的值,如果IoC容器已经初始化完成,那么这里的值肯定不是null
   WebApplicationContext rootContext =
         WebApplicationContextUtils.getWebApplicationContext(getServletContext());
   WebApplicationContext wac = null;

   if (this.webApplicationContext != null) {
        wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
   ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
   if (!cwac.isActive()) {
       //如果没有执行过webcontextapplication的refresh,那么再执行一次
    if (cwac.getParent() == null) {
         cwac.setParent(rootContext);
      }
      //这个过程就类似IOC的启动了
      configureAndRefreshWebApplicationContext(cwac);
   }
}
   }
   ...
   if (!this.refreshEventReceived) {
      //没有执行过refresh则执行一次
      onRefresh(wac);
   }
    ….
   return wac;
}

对于这个时间点的DispatcherServlet启动来说,核心在于 onRefresh,它会去初始化各种resolver

代码语言:javascript
复制
protected void onRefresh(ApplicationContext context) {
 …
initMultipartResolver(context);
...
initHandlerMappings(context);
...
initViewResolvers(context);
 …
}

MultipartResolver

它会从容器中读取是否包含 bean ‘multipartResolver'

代码语言:javascript
复制
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver”;
...
private void initMultipartResolver(ApplicationContext context) {
      ...
      this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
      ...
}

MultipartResolver是用来解决文件上传问题

HandlerMappings

默认自己去扫描所有HandlerMapping类型的

代码语言:javascript
复制
private void initHandlerMappings(ApplicationContext context) {
   this.handlerMappings = null;

   if (this.detectAllHandlerMappings) {
    //默认这里执行主动探测,这里的实现其实就是从BeanFactory中获取所有已经注册了的,且类型是HandlerMapping的类的名字,然后再从BeanFactory中获取所有这个名字的bean作为返回
      Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
      if (!matchingBeans.isEmpty()) {
         this.handlerMappings = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
      }
   }
   ...
  if (this.handlerMappings == null) {
      //没有handlerMapping,则使用默认的。
      this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
      if (logger.isTraceEnabled()) {
         logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
               "': using default strategies from DispatcherServlet.properties");
      }
   }
}

在没有配置的情况下,处理映射的类配置在spring自带的文件DispatcherServlet.properties中,默认handlerMapping的类为

代码语言:javascript
复制
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\   org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

HandlerMapping负责定义请求和处理请求的对象之间的映射

RequestMappingHandlerMapping为例。当获取到对应的名字后

代码语言:javascript
复制
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
   String key = strategyInterface.getName();
  //获取默认的配置
   String value = defaultStrategies.getProperty(key);
     ….
    //通过反射构建class对象
            Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
    //从beanFactory中获取对象,其实就是调用createBean方法
            Object strategy = createDefaultStrategy(context, clazz);
            strategies.add((T) strategy);
         }
        ….
}

对于beanFactory来说,创建一个bean或经历它的完整生命周期,经过多层查找,可以看到如下代码

代码语言:javascript
复制
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

    BeanWrapper instanceWrapper = null;
   ...
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   ...
   final Object bean = instanceWrapper.getWrappedInstance();
...
  Object exposedObject = bean;
...
      exposedObject = initializeBean(beanName, exposedObject, mbd);
...
}

执行一些列的生命名周期方法

代码语言:javascript
复制
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
   ...
   //执行各种aware方法
      invokeAwareMethods(beanName, bean);
   …
    //执行初始化之前的BeanPostProcessor相关方法
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   
   …
   //执行初始化bean方法
      invokeInitMethods(beanName, wrappedBean, mbd);
    …
    //执行初始化之后的BeanPostProcessor相关方法
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   ...

}

-aware 方法 private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } } 复制代码

初始化bean又包含了相关生命周期要执行的逻辑

代码语言:javascript
复制
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {

   boolean isInitializingBean = (bean instanceof InitializingBean);
   if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
          …
        //执行afterPropertiesSet
         ((InitializingBean) bean).afterPropertiesSet();
       ...
   }

   if (mbd != null && bean.getClass() != NullBean.class) {
      String initMethodName = mbd.getInitMethodName();
      if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
        //执行自己的initMethod方法
         invokeCustomInitMethod(beanName, bean, mbd);
      }
   }
}

对于 RequestMappingHandlerMapping 继承了接口ApplicationContextAwareInitializingBean,都属于bean生命周期中的一环。

ApplicationContextAware

RequestMappingHandlerMapping的父类自己持有一个applicationContext的引用

代码语言:javascript
复制
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
  ...
   else if (this.applicationContext == null) {
      ...
      this.applicationContext = context;
      this.messageSourceAccessor = new MessageSourceAccessor(context);
      initApplicationContext(context);
   }
  ...
}

从父类开始往下去执行对应的方法

代码语言:javascript
复制
protected void initApplicationContext() throws BeansException {
   …
   //探测所有的interceptor,即找到所有类MappedInterceptor【这对应 mvc-interceptor标签】和实现了接口HandlerInterceptor的拦截器
   detectMappedInterceptors(this.adaptedInterceptors);
   //初始化interceptor
   initInterceptors();
}

InitializingBean

代码语言:javascript
复制
public void afterPropertiesSet() {
    …
//getCandidateBeanNames默认就是获取所有的bean
for (String beanName : getCandidateBeanNames()) {
    //判断 bean 的名字是否是 “scopedTarget.” 字符串开头
   if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
      processCandidateBean(beanName);
   }
}
    …
}

查到bean后,开始识别是否是用来处理请求的

代码语言:javascript
复制
protected void processCandidateBean(String beanName) {
   Class<?> beanType = null;
     ...
      beanType = obtainApplicationContext().getType(beanName);
     …
   //isHandler即判断这个beanType是否包含注解 Controller 或者 RequestMapping
   if (beanType != null && isHandler(beanType)) {
    //找到这个注解bean的所有方法,构建映射关系
      detectHandlerMethods(beanName);
   }
}

protected boolean isHandler(Class<?> beanType) {
   return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
         AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

探测handler的方法分成两个主要部分

  1. 找到这个bean的所有的方法
  2. 将方法注册
代码语言:javascript
复制
protected void detectHandlerMethods(Object handler) {
      …
      //找到这个bean的方法
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> {
               try {
                //找到方法对应的RequestMapping注解,将它的path等参数封装成RequestMappingInfo返回
                  return getMappingForMethod(method, userType);
               }
               catch (Throwable ex) {
                  throw new IllegalStateException("Invalid mapping on handler class [" +
                        userType.getName() + "]: " + method, ex);
               }
            });
     ...
      methods.forEach((method, mapping) -> {
         Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
          //注册handler,在内部创建HandlerMethod,在urlLookup中存储 url和mapping的关系,而mapping和HandlerMethod则存储在mappingLookup中
         registerHandlerMethod(handler, invocableMethod, mapping);
      });
    ...
}

initViewResolvers

同handlerMapping,默认类为

代码语言:javascript
复制
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
复制代码

根据view的名字来找到对应的View。View则负责来渲染内容

spring 处理请求到来

Jetty请求过程可以看到,执行请求对应着的是servlet的service方法,对应spring来说,他就是DispatcherServlet

代码语言:javascript
复制
protected void doService(HttpServletRequest request, HttpServletResponse response) {
 …
//请求总设置applicationContext
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
…
//进行请求分发
doDispatch(request, response);
…
}
doDispatch负责把一次请求分配给对应的handler来处理
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  ...
      ModelAndView mv = null;
     ...
         //如果请求存在分段文件,则转换成Multipart,比如MultipartHttpServletRequest
         processedRequest = checkMultipart(request);
         …
        //获取对应请求的handler
         mappedHandler = getHandler(processedRequest);
        …
        //返回这个hander对应的适配器,比如对于HandlerMethod子类返回的就是AbstractHandlerMethodAdapter
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        …
        //调用interceptor的preHandle方法
     
        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
           return;
         }
        …
        //执行处理逻辑
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
         …
        //掉interceptor的postHandle方法
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      ….
    //处理结果
     processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
      ...
}

getHandler详细处理如下

代码语言:javascript
复制
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //内部根据请求的路径执行lookupHandlerMethod(lookupPath, request),而它就会从 urlLookup.get(urlPath)中查到对应的mapping,再查到HanlerMethod
   Object handler = getHandlerInternal(request);
   …
   //匹配路径的拦截器全都加到handler链路里面来 
   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
   ...
   return executionChain;
}

handler核心逻辑如下

代码语言:javascript
复制
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
      ...
       //将handlerMethod进行包装,以便后续通过反射执行
      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        。。。

      //创建ModelAndView的容器
      ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        …
        //通过反射执行
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      …
      //获取ModeAndView,从内部可以看到,它会自行创建一个ModelAndView对象
      return getModelAndView(mavContainer, modelFactory, webRequest);
     ...
}

获得handler的结果之后,调用processDispatchResult,核心就是进行render

代码语言:javascript
复制
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
      @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
      @Nullable Exception exception) throws Exception {
      ...
      render(mv, request, response);
      ...
}

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
  ….
   View view;
    //获取视图的名字
   String viewName = mv.getViewName();
    //根据名字获取对应的视图
   view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
    …
    //执行渲染
      view.render(mv.getModelInternal(), request, response);
 ...
}

执行render方法来源与所有render的父类AbstractView的render方法

代码语言:javascript
复制
@Overridepublic void render(@Nullable Map<String, ?> model, HttpServletRequest request,
      HttpServletResponse response) throws Exception {
    ….
   Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
   prepareResponse(request, response);
   //真正执行渲染
   renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}

比如返回的是JSON对象,那么实际情况如下

代码语言:javascript
复制
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    Object value = this.filterModel(model);
    //值封装成json
    String text = JSON.toJSONString(value, this.serializerFeatures);
    byte[] bytes = text.getBytes(this.charset);
    Object stream = this.updateContentLength?this.createTemporaryOutputStream():response.getOutputStream();
    //结果写入outpuststream
    ((OutputStream)stream).write(bytes);
    if(this.updateContentLength) {
        //返回
        this.writeToResponse(response, (ByteArrayOutputStream)stream);
    }

}

对于Freemarker来说,就是执行FreemarkerView.renderMergedTemplateModel方法,内部执行doRender

代码语言:javascript
复制
protected void doRender(Map<String, Object> model, HttpServletRequest request,
      HttpServletResponse response) throws Exception {

    exposeModelAsRequestAttributes(model, request);
    SimpleHash fmModel = buildTemplateModel(model, request, response);

    Locale locale = RequestContextUtils.getLocale(request);
    //这里就是调用Freemarker的template来处理对应的数据填充等等 template.process(model, response.getWriter());
   processTemplate(getTemplate(locale), fmModel, response);
}

至此一次请求结束

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018年10月30日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MultipartResolver
  • HandlerMappings
  • ApplicationContextAware
  • InitializingBean
  • initViewResolvers
  • spring 处理请求到来
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档