码迷,mamicode.com
首页 > 编程语言 > 详细

Spring MVC DispatcherServlet

时间:2018-03-31 20:32:21      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:services   val   after   UI   explicit   sla   OLE   handle   refresh   

  • DispatcherServlet UML图

技术分享图片

本次分析:HttpServlet->HttpServletBean->FramworkServlet->DispacherServlet

  • ServletContext是什么?
    ServletContext,是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。

  • WebApplicationContext是什么?
    顾名思义WebApplicationContext是依赖于Web容器的一个Spring的IOC容器。前提条件是web容器启动后这个容器才能启动。那么如何借助web容器来启动Spring web的上下文?

  • HttpServletBean类

    public final void init() throws ServletException {
        if(this.logger.isDebugEnabled()) {
            this.logger.debug("Initializing servlet ‘" + this.getServletName() + "‘");
        }
    
        //将Servlet初始化参数设置到该组件上
        PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
        if(!pvs.isEmpty()) {
            try {
                BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
                bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
                this.initBeanWrapper(bw);
                bw.setPropertyValues(pvs, true);
            } catch (BeansException var4) {
                if(this.logger.isErrorEnabled()) {
                    this.logger.error("Failed to set bean properties on servlet ‘" + this.getServletName() + "‘", var4);
                }
    
                throw var4;
            }
        }
    
        //交给子类初始化,FrameworkServlet子类的方法覆盖
        this.initServletBean();
        if(this.logger.isDebugEnabled()) {
            this.logger.debug("Servlet ‘" + this.getServletName() + "‘ configured successfully");
        }
    
    }
  • FrameworkServlet类

     protected final void initServletBean() throws ServletException {
        //省略
        //
        try {
            //初始化web上下文
            this.webApplicationContext = this.initWebApplicationContext();
            //初始化
            this.initFrameworkServlet();
        } 
        
        //省略
    protected WebApplicationContext initWebApplicationContext() {
        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()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent -> set
                        // the root application context (if any; may be null) as the parent
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            //查找已经绑定的上下文
            wac = findWebApplicationContext();
        }
        if (wac == null) {
            // No context instance is defined for this servlet -> create a local one 指定为ContextLoaderListener  
            wac = createWebApplicationContext(rootContext);
        }

        if (!this.refreshEventReceived) {
            // Either the context is not a ConfigurableApplicationContext with refresh
            // support or the context injected at construction time had already been
            // refreshed -> trigger initial onRefresh manually here.
            onRefresh(wac);
        }

        if (this.publishContext) {
            // Publish the context as a servlet context attribute.
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Published WebApplicationContext of servlet ‘" + getServletName() +
                        "‘ as ServletContext attribute with name [" + attrName + "]");
            }
        }

        return wac;
    }

从initWebApplicationContext()方法可以看出,基本上如果ContextLoaderListener加载了上下文将作为根上下文(DispatcherServlet的父容器)。

技术分享图片

  • DispatcherServlet类
    ```
    **
    • This implementation calls {@link #initStrategies}.
      */
      @Override
      //FrameworkServlet中的wac
      protected void onRefresh(ApplicationContext context) {
      initStrategies(context);
      }
    /**
    • Initialize the strategy objects that this servlet uses.
    • May be overridden in subclasses in order to initialize further strategy objects.
      */
      protected void initStrategies(ApplicationContext context) {
      initMultipartResolver(context);
      initLocaleResolver(context);
      initThemeResolver(context);
      //将两种类型的Bean从context里取出来
      initHandlerMappings(context);
      initHandlerAdapters(context);
      initHandlerExceptionResolvers(context);
      initRequestToViewNameTranslator(context);
      initViewResolvers(context);
      initFlashMapManager(context);
      }


doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //省略...

    try {
        //省略...

        try {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // Determine handler for the current request.
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

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

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            //调用所有拦截器的prehandle
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

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

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            //调用注册的所有拦截器的posthandle方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        
        //省略...
        //render绘制MV
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    
    //省略...
    
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        
        //省略...
    }
}

```
1.容器启动时,找到配置文件中的context-param作为键值对放到ServletContext中
2.然后找到listener,容器调用它的contextInitialized(ServletContextEvent event)方法,执行其中的操作
3.spring为我们提供了实现ServletContextListener接口的上下文初始化监听器:ContextLoaderListener

4.spring为我们提供的IOC容器,需要我们指定容器的配置文件,然后由该监听器初始化并创建该容器。要求你指定配置文件的地址及文件名称,一定要使用:contextConfigLocation作为参数名称。

  • spring上下文容器配置后,初始化了什么

1、servlet容器启动,为应用创建一个“全局上下文环境”:ServletContext
2、容器调用web.xml中配置的contextLoaderListener,初始化WebApplicationContext上下文环境(即IOC容器),加载context-param指定的配置文件信息到IOC容器中。WebApplicationContext在ServletContext中以键值对的形式保存
3、容器初始化web.xml中配置的servlet,为其初始化自己的上下文信息servletContext,并加载其设置的配置信息到该上下文中。将WebApplicationContext设置为它的父容器。
4、此后的所有servlet的初始化都按照3步中方式创建,初始化自己的上下文环境,将WebApplicationContext设置为自己的父上下文环境。

技术分享图片

Spring MVC DispatcherServlet

标签:services   val   after   UI   explicit   sla   OLE   handle   refresh   

原文地址:https://www.cnblogs.com/boycelee/p/8683734.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!