DispatcherServlet

来源:互联网 发布:杜月笙评价知乎 编辑:程序博客网 时间:2024/06/10 10:37

DispatcherServlet初始化顺序

继承体系结构如下所示:

 

1、HttpServletBean继承HttpServlet因此在Web容器启动时将调用它的init方法,该初始化方法的主要作用

:::将Servlet初始化参数(init-param)设置到该组件上(如contextAttribute、contextClass、namespace、contextConfigLocation),通过BeanWrapper简化设值过程,方便后续使用;

:::提供给子类初始化扩展点,initServletBean(),该方法由FrameworkServlet覆盖。

 

public abstract class HttpServletBean extends HttpServlet implements EnvironmentAware{@Override    public final void init() throws ServletException {       //省略部分代码       //1、如下代码的作用是将Servlet初始化参数设置到该组件上//如contextAttribute、contextClass、namespace、contextConfigLocation;       try {           PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);           BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);           ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());           bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));           initBeanWrapper(bw);           bw.setPropertyValues(pvs, true);       }       catch (BeansException ex) {           //…………省略其他代码       }       //2、提供给子类初始化的扩展点,该方法由FrameworkServlet覆盖       initServletBean();       if (logger.isDebugEnabled()) {           logger.debug("Servlet '" + getServletName() + "' configured successfully");       }    }    //…………省略其他代码}

   

2、FrameworkServlet继承HttpServletBean通过initServletBean()进行Web上下文初始化,该方法主要覆盖一下两件事情:

    初始化web上下文;

    提供给子类初始化扩展点;

public abstract class FrameworkServlet extends HttpServletBean {@Override    protected final void initServletBean() throws ServletException {        //省略部分代码       try {             //1、初始化Web上下文           this.webApplicationContext = initWebApplicationContext();             //2、提供给子类初始化的扩展点           initFrameworkServlet();       }        //省略部分代码    }}

 

protected WebApplicationContext initWebApplicationContext() {        //ROOT上下文(ContextLoaderListener加载的)       WebApplicationContext rootContext =              WebApplicationContextUtils.getWebApplicationContext(getServletContext());       WebApplicationContext wac = null;       if (this.webApplicationContext != null) {           // 1、在创建该Servlet注入的上下文           wac = this.webApplicationContext;           if (wac instanceof ConfigurableWebApplicationContext) {              ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;              if (!cwac.isActive()) {                  if (cwac.getParent() == null) {                      cwac.setParent(rootContext);                  }                  configureAndRefreshWebApplicationContext(cwac);              }           }       }       if (wac == null) {             //2、查找已经绑定的上下文           wac = findWebApplicationContext();       }       if (wac == null) {            //3、如果没有找到相应的上下文,并指定父亲为ContextLoaderListener           wac = createWebApplicationContext(rootContext);       }       if (!this.refreshEventReceived) {             //4、刷新上下文(执行一些初始化)           onRefresh(wac);       }       if (this.publishContext) {           // Publish the context as a servlet context attribute.           String attrName = getServletContextAttributeName();           getServletContext().setAttribute(attrName, wac);           //省略部分代码       }       return wac;    }

  

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

最后调用了onRefresh()方法执行容器的一些初始化,这个方法由子类实现,来进行扩展。

  

3、DispatcherServlet继承FrameworkServlet,并实现了onRefresh()方法提供一些前端控制器相关的配置: 

public class DispatcherServlet extends FrameworkServlet {     //实现子类的onRefresh()方法,该方法委托为initStrategies()方法。    @Override    protected void onRefresh(ApplicationContext context) {       initStrategies(context);    }     //初始化默认的Spring Web MVC框架使用的策略(如HandlerMapping)    protected void initStrategies(ApplicationContext context) {       initMultipartResolver(context);       initLocaleResolver(context);       initThemeResolver(context);       initHandlerMappings(context);       initHandlerAdapters(context);       initHandlerExceptionResolvers(context);       initRequestToViewNameTranslator(context);       initViewResolvers(context);       initFlashMapManager(context);    }}

  

从如上代码可以看出,DispatcherServlet启动时会进行我们需要的Web层Bean的配置,如HandlerMapping、HandlerAdapter等,而且如果我们没有配置,还会给我们提供默认的配置。

 

从如上代码我们可以看出,整个DispatcherServlet初始化的过程和做了些什么事情,具体主要做了如下两件事情:

1、初始化Spring Web MVC使用的Web上下文,并且可能指定父容器为(ContextLoaderListener加载了根上下文);

2、初始化DispatcherServlet使用的策略,如HandlerMapping、HandlerAdapter等。 

 

服务器启动时的日志分析(此处加上了ContextLoaderListener从而启动ROOT上下文容器): 

 信息: Initializing Spring root WebApplicationContext //ContextLoaderListener启动ROOT上下文

 

2012-03-12 13:33:55 [main] INFO  org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started

2012-03-12 13:33:55 [main] INFO  org.springframework.web.context.support.XmlWebApplicationContext - Refreshing Root WebApplicationContext: startup date [Mon Mar 12 13:33:55 CST 2012]; root of context hierarchy

2012-03-12 13:33:55 [main] DEBUG org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader - Loading bean definitions

2012-03-12 13:33:55 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 0 bean definitions from location pattern [/WEB-INF/ContextLoaderListener.xml]

2012-03-12 13:33:55 [main] DEBUG org.springframework.web.context.support.XmlWebApplicationContext - Bean factory for Root WebApplicationContext: org.springframework.beans.factory.support.DefaultListableBeanFactory@1c05ffd: defining beans []; root of factory hierarchy

2012-03-12 13:33:55 [main] DEBUG org.springframework.web.context.support.XmlWebApplicationContext - Bean factory for Root WebApplicationContext:

2012-03-12 13:33:55 [main] DEBUG org.springframework.web.context.ContextLoader - Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT] //ROOT上下文绑定到ServletContext

2012-03-12 13:33:55 [main] INFO  org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 438 ms  //到此ROOT上下文启动完毕

 

 2012-03-12 13:33:55 [main] DEBUG org.springframework.web.servlet.DispatcherServlet - Initializing servlet 'chapter2'

信息: Initializing Spring FrameworkServlet 'chapter2'  //开始初始化FrameworkServlet对应的Web上下文

2012-03-12 13:33:55 [main] INFO  org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'chapter2': initialization started

2012-03-12 13:33:55 [main] DEBUG org.springframework.web.servlet.DispatcherServlet - Servlet with name 'chapter2' will try to create custom WebApplicationContext context of class 'org.springframework.web.context.support.XmlWebApplicationContext', using parent context [Root WebApplicationContext: startup date [Mon Mar 12 13:33:55 CST 2012]; root of context hierarchy]

//此处使用Root WebApplicationContext作为父容器。

2012-03-12 13:33:55 [main] INFO  org.springframework.web.context.support.XmlWebApplicationContext - Refreshing WebApplicationContext for namespace 'chapter2-servlet': startup date [Mon Mar 12 13:33:55 CST 2012]; parent: Root WebApplicationContext

2012-03-12 13:33:55 [main] INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/chapter2-servlet.xml]

2012-03-12 13:33:55 [main] DEBUG org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader - Loading bean definitions

2012-03-12 13:33:55 [main] DEBUG org.springframework.beans.factory.xml.BeanDefinitionParserDelegate - Neither XML 'id' nor 'name' specified - using generated bean name[org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping#0]  //我们配置的HandlerMapping

2012-03-12 13:33:55 [main] DEBUG org.springframework.beans.factory.xml.BeanDefinitionParserDelegate - Neither XML 'id' nor 'name' specified - using generated bean name[org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter#0] //我们配置的HandlerAdapter

2012-03-12 13:33:55 [main] DEBUG org.springframework.beans.factory.xml.BeanDefinitionParserDelegate - Neither XML 'id' nor 'name' specified - using generated bean name [org.springframework.web.servlet.view.InternalResourceViewResolver#0] //我们配置的ViewResolver

2012-03-12 13:33:55 [main] DEBUG org.springframework.beans.factory.xml.BeanDefinitionParserDelegate - No XML 'id' specified - using '/hello' as bean name and [] as aliases 

//我们的处理器(HelloWorldController

2012-03-12 13:33:55 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 4 bean definitions from location pattern [/WEB-INF/chapter2-servlet.xml]

2012-03-12 13:33:55 [main] DEBUG org.springframework.web.context.support.XmlWebApplicationContext - Bean factory for WebApplicationContext for namespace 'chapter2-servlet': org.springframework.beans.factory.support.DefaultListableBeanFactory@1372656: defining beans [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping#0,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter#0,org.springframework.web.servlet.view.InternalResourceViewResolver#0,/hello]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@1c05ffd

//到此容器注册的Bean初始化完毕

 

2012-03-12 13:33:56 [main] DEBUG org.springframework.web.servlet.DispatcherServlet - Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided

 

2012-03-12 13:33:56 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver'

//默认的LocaleResolver注册

2012-03-12 13:33:56 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'org.springframework.web.servlet.theme.FixedThemeResolver'

//默认的ThemeResolver注册

 

2012-03-12 13:33:56 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping#0'

//发现我们定义的HandlerMapping 不再使用默认的HandlerMapping

 

2012-03-12 13:33:56 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter#0'

//发现我们定义的HandlerAdapter 不再使用默认的HandlerAdapter

 

2012-03-12 13:33:56 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver'

//异常处理解析器ExceptionResolver

2012-03-12 13:33:56 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver'

 

2012-03-12 13:33:56 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.web.servlet.view.InternalResourceViewResolver#0'

 

2012-03-12 13:33:56 [main] DEBUG org.springframework.web.servlet.DispatcherServlet - Published WebApplicationContext of servlet 'chapter2' as ServletContext attribute with name [org.springframework.web.servlet.FrameworkServlet.CONTEXT.chapter2]

//绑定FrameworkServlet初始化的Web上下文到ServletContext

2012-03-12 13:33:56 [main] INFO  org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'chapter2': initialization completed in  297 ms

2012-03-12 13:33:56 [main] DEBUG org.springframework.web.servlet.DispatcherServlet - Servlet 'chapter2' configured successfully

//到此完整流程结束 

  

从如上日志我们也可以看出,DispatcherServlet会进行一些默认的配置。接下来我们看一下默认配置吧。

  

3.5、DispatcherServlet默认配置

DispatcherServlet的默认配置在DispatcherServlet.properties(和DispatcherServlet类在一个包下)中,而且是当Spring配置文件中没有指定配置时使用的默认策略:

 

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

   

从如上配置可以看出DispatcherServlet在启动时会自动注册这些特殊的Bean,无需我们注册,如果我们注册了,默认的将不会注册。 

因此如第二章的BeanNameUrlHandlerMapping、SimpleControllerHandlerAdapter是不需要注册的,DispatcherServlet默认会注册这两个Bean。

 

从DispatcherServlet.properties可以看出有许多特殊的Bean,那接下来我们就看看Spring Web MVC主要有哪些特殊的Bean。

3.6、DispatcherServlet中使用的特殊的Bean

DispatcherServlet默认使用WebApplicationContext作为上下文,因此我们来看一下该上下文中有哪些特殊的Bean:

1、Controller处理器/页面控制器,做的是MVC中的C的事情,但控制逻辑转移到前端控制器了,用于对请求进行处理;

2、HandlerMapping请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象;如BeanNameUrlHandlerMapping将URL与Bean名字映射,映射成功的Bean就是此处的处理器;

3、HandlerAdapterHandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;如SimpleControllerHandlerAdapter将对实现了Controller接口的Bean进行适配,并且掉处理器的handleRequest方法进行功能处理;

4、ViewResolverViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;如InternalResourceViewResolver将逻辑视图名映射为jsp视图;

5、LocalResover本地化解析,因为Spring支持国际化,因此LocalResover解析客户端的Locale信息从而方便进行国际化;

6、ThemeResovler主题解析,通过它来实现一个页面多套风格,即常见的类似于软件皮肤效果;

7、MultipartResolver文件上传解析,用于支持文件上传;

8HandlerExceptionResolver处理器异常解析,可以将异常映射到相应的统一错误界面,从而显示用户友好的界面(而不是给用户看到具体的错误信息);

9RequestToViewNameTranslator当处理器没有返回逻辑视图名等相关信息时,自动将请求URL映射为逻辑视图名;

10FlashMapManager用于管理FlashMap的策略接口,FlashMap用于存储一个请求的输出,当进入另一个请求时作为该请求的输入,通常用于重定向场景,后边会细述。

  

到此DispatcherServlet我们已经了解了,接下来我们就需要把上边提到的特殊Bean挨个击破,那首先从控制器开始吧。

 

==========================以上部分来自跟开涛学MVC==================================

==================================哥是分割线========================================

 

 主要方法和类分析:

DispatcherServlet启动时,会依次加载配置文件中所有的Resolver(包括MultipartResolver,LocaleResolver,ThemeResolver)、HandlerMappings、HandlerAdapter、HandlerExceptionResolver、ViewResolver,若没有,则会提供默认的相应配置

 如:

protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}

 

 其中,这三个Resolver(MultipartResolver,LocaleResolver,ThemeResolver)是直接通过bean加载

 

private void initLocaleResolver(ApplicationContext context) {try {this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);if (logger.isDebugEnabled()) {logger.debug("Using LocaleResolver [" + this.localeResolver + "]");}}catch (NoSuchBeanDefinitionException ex) {// We need to use the default.this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);if (logger.isDebugEnabled()) {logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +"': using default [" + this.localeResolver + "]");}}}public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";

 

而HandlerMappings、HandlerAdapters、HandlerExceptionResolvers则是通过通用方法构造一个相应的Map,如Map<String, HandlerMapping>,Map<String, HandlerAdapter>等,然后获得所有的handlerMappings / handlerAdapters.. List对象,如:

private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;if (this.detectAllHandlerMappings) {// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());// We keep HandlerMappings in sorted order.OrderComparator.sort(this.handlerMappings);}}else {try {HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);this.handlerMappings = Collections.singletonList(hm);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerMapping later.}}// Ensure we have at least one HandlerMapping, by registering// a default HandlerMapping if no other mappings are found.if (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isDebugEnabled()) {logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");}}}

 

Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);

 当没有找到HandlerMapping等时,会从DispatcherServlet.properties找到一个默认的Mapping,另两个也是

private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";private static final Properties defaultStrategies;static {// Load default strategy implementations from properties file.// This is currently strictly internal and not meant to be customized// by application developers.try {ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);}catch (IOException ex) {throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());}}

 

// Ensure we have at least one HandlerMapping, by registering// a default HandlerMapping if no other mappings are found.if (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isDebugEnabled()) {logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");}}

 

/** * Create a List of default strategy objects for the given strategy interface. * <p>The default implementation uses the "DispatcherServlet.properties" file (in the same * package as the DispatcherServlet class) to determine the class names. It instantiates * the strategy objects through the context's BeanFactory. * @param context the current WebApplicationContext * @param strategyInterface the strategy interface * @return the List of corresponding strategy objects */@SuppressWarnings("unchecked")protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {String key = strategyInterface.getName();String value = defaultStrategies.getProperty(key);if (value != null) {String[] classNames = StringUtils.commaDelimitedListToStringArray(value);List<T> strategies = new ArrayList<T>(classNames.length);for (String className : classNames) {try {Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());Object strategy = createDefaultStrategy(context, clazz);strategies.add((T) strategy);}catch (ClassNotFoundException ex) {throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className +"] for interface [" + key + "]", ex);}catch (LinkageError err) {throw new BeanInitializationException("Error loading DispatcherServlet's default strategy class [" + className +"] for interface [" + key + "]: problem with class file or dependent class", err);}}return strategies;}else {return new LinkedList<T>();}}

 

/** * Create a default strategy. * <p>The default implementation uses {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean}. * @param context the current WebApplicationContext * @param clazz the strategy implementation class to instantiate * @return the fully configured strategy instance * @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory() * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean */protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {return context.getAutowireCapableBeanFactory().createBean(clazz);}

 

 DispatcherServlet中最主要的核心功能是由doServicedoDispatch实现的。

 

当请求到达后HttpServlet将调用service方法进行处理,由于我们是通过输入网址方式的get方法请求,Servlet将调用doGet方法

此处的doGet方法在FrameworkServlet中实现,doGet方法调用processRequest方法,

processRequest则调用doService方法处理,而doService在DispatcherServlet中实现,

doService再调用了DispatcherServlet的doDispatch方法,该方法则会根据request找到转发对象,并进行请求转发操作,

dispatcherservlet中无论是通过post方式还是get方式提交的request,最终都会交由doservice()处理。

 

具体流程如下:

 

//HttpServletprotected void service(HttpServletRequest req, HttpServletResponse resp)        throws ServletException, IOException    {        String method = req.getMethod();        if (method.equals(METHOD_GET)) {            long lastModified = getLastModified(req);            if (lastModified == -1) {                // servlet doesn't support if-modified-since, no reason                // to go through further expensive logic                doGet(req, resp);            } else {                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);                if (ifModifiedSince < lastModified) {                    // If the servlet mod time is later, call doGet()                    // Round down to the nearest second for a proper compare                    // A ifModifiedSince of -1 will always be less                    maybeSetLastModified(resp, lastModified);                    doGet(req, resp);                } else {                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);                }            }        } else if (method.equals(METHOD_HEAD)) {            long lastModified = getLastModified(req);            maybeSetLastModified(resp, lastModified);            doHead(req, resp);        } else if (method.equals(METHOD_POST)) {            doPost(req, resp);                    } else if (method.equals(METHOD_PUT)) {            doPut(req, resp);                    } else if (method.equals(METHOD_DELETE)) {            doDelete(req, resp);                    } else if (method.equals(METHOD_OPTIONS)) {            doOptions(req,resp);                    } else if (method.equals(METHOD_TRACE)) {            doTrace(req,resp);                    } else {            //            // Note that this means NO servlet supports whatever            // method was requested, anywhere on this server.            //            String errMsg = lStrings.getString("http.method_not_implemented");            Object[] errArgs = new Object[1];            errArgs[0] = method;            errMsg = MessageFormat.format(errMsg, errArgs);                        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);        }    }

 

//FrameworkServlet@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {long startTime = System.currentTimeMillis();Throwable failureCause = null;LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();LocaleContext localeContext = buildLocaleContext(request);RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());initContextHolders(request, localeContext, requestAttributes);try {doService(request, response);}catch (ServletException ex) {failureCause = ex;throw ex;}catch (IOException ex) {failureCause = ex;throw ex;}catch (Throwable ex) {failureCause = ex;throw new NestedServletException("Request processing failed", ex);}finally {resetContextHolders(request, previousLocaleContext, previousAttributes);if (requestAttributes != null) {requestAttributes.requestCompleted();}if (logger.isDebugEnabled()) {if (failureCause != null) {this.logger.debug("Could not complete request", failureCause);}else {if (asyncManager.isConcurrentHandlingStarted()) {logger.debug("Leaving response open for concurrent processing");}else {this.logger.debug("Successfully completed request");}}}publishRequestHandledEvent(request, startTime, failureCause);}}

 

 DispatcherServlet中doService:

@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) {String requestUri = urlPathHelper.getRequestUri(request);String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +" processing " + request.getMethod() + " request for [" + requestUri + "]");}// Keep a snapshot of the request attributes in case of an include,// to be able to restore the original attributes after the include.Map<String, Object> attributesSnapshot = null;if (WebUtils.isIncludeRequest(request)) {logger.debug("Taking snapshot of request attributes before include");attributesSnapshot = new HashMap<String, Object>();Enumeration<?> attrNames = request.getAttributeNames();while (attrNames.hasMoreElements()) {String attrName = (String) attrNames.nextElement();if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {attributesSnapshot.put(attrName, request.getAttribute(attrName));}}}// Make framework objects available to handlers and view objects.request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);if (inputFlashMap != null) {request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));}request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);try {doDispatch(request, response);}finally {if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {return;}// Restore the original attribute snapshot, in case of an include.if (attributesSnapshot != null) {restoreAttributesAfterInclude(request, attributesSnapshot);}}}

 

 doDispatch方法:处理拦截,转发请求,并绘制VIEW

 

 doDispatch()中的处理逻辑大致分以下几个步骤:

1.根据request得到相应的处理器

 HandlerExecutionChain  mappedhandler = getHandler(request)

2.调用注册的所有拦截器的prehandle方法

if (!mappedHandler.applyPreHandle(processedRequest, response))

 

3.调用处理器 

 

//这里使用了adapter模式

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

 

4.调用注册的所有拦截器的posthandle方法

mappedHandler.applyPostHandle(processedRequest, response, mv);

 

5.绘制mv

render(mv, request, response);

 

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;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()) {String requestUri = urlPathHelper.getRequestUri(request);logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}try {// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());}finally {if (asyncManager.isConcurrentHandlingStarted()) {return;}}applyDefaultViewName(request, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Error err) {triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionmappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);return;}// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {for (HandlerMapping hm : this.handlerMappings) {if (logger.isTraceEnabled()) {logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");}HandlerExecutionChain handler = hm.getHandler(request);if (handler != null) {return handler;}}return null;}

参考:

SpringMVC中DispatcherServlet工作原理探究

spring中dispatcherservlet的运行机制

 

 几个实例对象:

1个HandlerMapping有1个HandlerExecutionChain

HandlerExecutionChain下有多个过滤器HandlerInterceptor

 

过滤器HandlerInterceptor下有前置方法和后置方法

public interface HandlerMapping {/** * Return a handler and any interceptors for this request. The choice may be made * on request URL, session state, or any factor the implementing class chooses. * <p>The returned HandlerExecutionChain contains a handler Object, rather than * even a tag interface, so that handlers are not constrained in any way.  */HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;}

 

public class HandlerExecutionChain {private final Object handler;private HandlerInterceptor[] interceptors;private List<HandlerInterceptor> interceptorList;private int interceptorIndex = -1;public HandlerExecutionChain(Object handler) {this(handler, null);}public HandlerExecutionChain(Object handler, HandlerInterceptor[] interceptors) {if (handler instanceof HandlerExecutionChain) {HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;this.handler = originalChain.getHandler();this.interceptorList = new ArrayList<HandlerInterceptor>();CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);}else {this.handler = handler;this.interceptors = interceptors;}}public Object getHandler() {return this.handler;}public void addInterceptor(HandlerInterceptor interceptor) {initInterceptorList();this.interceptorList.add(interceptor);}public void addInterceptors(HandlerInterceptor[] interceptors) {if (interceptors != null) {initInterceptorList();this.interceptorList.addAll(Arrays.asList(interceptors));}}private void initInterceptorList() {if (this.interceptorList == null) {this.interceptorList = new ArrayList<HandlerInterceptor>();}if (this.interceptors != null) {this.interceptorList.addAll(Arrays.asList(this.interceptors));this.interceptors = null;}}/** * Return the array of interceptors to apply (in the given order). * @return the array of HandlerInterceptors instances (may be {@code null}) */public HandlerInterceptor[] getInterceptors() {if (this.interceptors == null && this.interceptorList != null) {this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);}return this.interceptors;}/** * 过滤器前置方法 */boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {if (getInterceptors() != null) {for (int i = 0; i < getInterceptors().length; i++) {HandlerInterceptor interceptor = getInterceptors()[i];if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}}return true;}/** * 过滤器后置方法 */void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {if (getInterceptors() == null) {return;}for (int i = getInterceptors().length - 1; i >= 0; i--) {HandlerInterceptor interceptor = getInterceptors()[i];interceptor.postHandle(request, response, this.handler, mv);}}/** * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. * Will just invoke afterCompletion for all interceptors whose preHandle invocation * has successfully completed and returned true. */void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)throws Exception {if (getInterceptors() == null) {return;}for (int i = this.interceptorIndex; i >= 0; i--) {HandlerInterceptor interceptor = getInterceptors()[i];try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}/** * Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors. */void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {if (getInterceptors() == null) {return;}for (int i = getInterceptors().length - 1; i >= 0; i--) {if (interceptors[i] instanceof AsyncHandlerInterceptor) {try {AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) this.interceptors[i];asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);}catch (Throwable ex) {logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);}}}}}

   适配器:

public interface HandlerAdapter {/** * 处理请求Controller业务逻辑 */ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;}

 

public interface HandlerInterceptor {/** * Intercept the execution of a handler. Called after HandlerMapping determined * an appropriate handler object, but before HandlerAdapter invokes the handler.  */boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)    throws Exception;    /** * Intercept the execution of a handler. Called after HandlerAdapter actually * invoked the handler, but before the DispatcherServlet renders the view. */void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;/** * Callback after completion of request processing, that is, after rendering * */void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;}

 

 

// 包含一个View对象和一个Map//其中setViewName设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面public class ModelAndView {private Object view;private ModelMap model;public ModelAndView(String viewName) {this.view = viewName;}public ModelAndView(View view) {this.view = view;}public ModelAndView(String viewName, Map<String, ?> model) {this.view = viewName;if (model != null) {getModelMap().addAllAttributes(model);}}public ModelAndView(View view, Map<String, ?> model) {this.view = view;if (model != null) {getModelMap().addAllAttributes(model);}}/** * Convenient constructor to take a single model object. * @param viewName name of the View to render, to be resolved * by the DispatcherServlet's ViewResolver * @param modelName name of the single entry in the model * @param modelObject the single model object */public ModelAndView(String viewName, String modelName, Object modelObject) {this.view = viewName;addObject(modelName, modelObject);}/** * Convenient constructor to take a single model object. * @param view View object to render * @param modelName name of the single entry in the model * @param modelObject the single model object */public ModelAndView(View view, String modelName, Object modelObject) {this.view = view;addObject(modelName, modelObject);}/** * Set a view name for this ModelAndView, to be resolved by the * DispatcherServlet via a ViewResolver. Will override any * pre-existing view name or View. */public void setViewName(String viewName) {this.view = viewName;}/** * Return the view name to be resolved by the DispatcherServlet * via a ViewResolver, or {@code null} if we are using a View object. */public String getViewName() {return (this.view instanceof String ? (String) this.view : null);}/** * Set a View object for this ModelAndView. Will override any * pre-existing view name or View. */public void setView(View view) {this.view = view;}/** * Return the View object, or {@code null} if we are using a view name * to be resolved by the DispatcherServlet via a ViewResolver. */public View getView() {return (this.view instanceof View ? (View) this.view : null);}/** * Indicate whether or not this {@code ModelAndView} has a view, either * as a view name or as a direct {@link View} instance. */public boolean hasView() {return (this.view != null);}/** * Return whether we use a view reference, i.e. {@code true} * if the view has been specified via a name to be resolved by the * DispatcherServlet via a ViewResolver. */public boolean isReference() {return (this.view instanceof String);}/** * Return the model map. May return {@code null}. * Called by DispatcherServlet for evaluation of the model. */protected Map<String, Object> getModelInternal() {return this.model;}/** * Return the underlying {@code ModelMap} instance (never {@code null}). */public ModelMap getModelMap() {if (this.model == null) {this.model = new ModelMap();}return this.model;}/** * Return the model map. Never returns {@code null}. * To be called by application code for modifying the model. */public Map<String, Object> getModel() {return getModelMap();}/** * Add an attribute to the model. * @param attributeName name of the object to add to the model * @param attributeValue object to add to the model (never {@code null}) * @see ModelMap#addAttribute(String, Object) * @see #getModelMap() */public ModelAndView addObject(String attributeName, Object attributeValue) {getModelMap().addAttribute(attributeName, attributeValue);return this;}/** * Add an attribute to the model using parameter name generation. * @param attributeValue the object to add to the model (never {@code null}) * @see ModelMap#addAttribute(Object) * @see #getModelMap() */public ModelAndView addObject(Object attributeValue) {getModelMap().addAttribute(attributeValue);return this;}/** * Add all attributes contained in the provided Map to the model. * @param modelMap a Map of attributeName -> attributeValue pairs * @see ModelMap#addAllAttributes(Map) * @see #getModelMap() */public ModelAndView addAllObjects(Map<String, ?> modelMap) {getModelMap().addAllAttributes(modelMap);return this;}}

 

public interface ViewResolver {/** * Resolve the given view by name. * 从viewName获取View */View resolveViewName(String viewName, Locale locale) throws Exception;}

 

public interface View {/** * Render the view given the specified model. * 渲染页面 */void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;}

 ..

 

 

 

0 0