`

spring源码学习系列3.3-DispatcherServlet初始化-设计模式

 
阅读更多
springmvc的核心是DispatcherServlet

研究DispatcherServlet的设计分2个角度

1.DispatcherServlet的初始化

2.DispatcherServlet的访问


DispatcherServlet的初始化可以用模板方法设计模式概括

DispatcherServlet#init
@Override
	public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}

		// Set bean properties from init parameters.
		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) {
			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			throw ex;
		}

		// Let subclasses do whatever initialization they like.
		initServletBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}

protected void initServletBean() throws ServletException {
    }




将initServletBean设计为空方法,子类可以有选择的实现。




FrameworkServlet#initServletBean
@Override
	protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
		if (this.logger.isInfoEnabled()) {
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			this.webApplicationContext = initWebApplicationContext();
			initFrameworkServlet();
		}
		catch (ServletException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}
		catch (RuntimeException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (this.logger.isInfoEnabled()) {
			long elapsedTime = System.currentTimeMillis() - startTime;
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
					elapsedTime + " ms");
		}
	}



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





DispatcherServlet的访问可以通过模板方法,适配器设计模式概括

HttpSservlet#service
protected 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#doGet#processRequest
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);
		}
	}

protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
			throws Exception;



DispatcherServlet#doService
@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
			logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
					" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
		}

		// 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)) {
			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()) {
				// Restore the original attribute snapshot, in case of an include.
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}



DispatcherServlet#doDispatch
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, false);
				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;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

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

				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 afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}



通过适配器模式执行controller层实例
controller层执行常用适配器模式,如:
SimpleControllerHandlerAdapter  实现了Controller.
MultiActionController比直接实现Controller效率低,因为MultiActionController比单纯实现Controller的逻辑多,并且用到了反射,对于效率有要求的应尽量使用直接实现Controller

AnnotationMethodHandlerAdapter

SimpleServletHandlerAdapter   实现了Servlet


Controller层的设计采用了模板方法设计模式.父类AbstractController定义了算法的架构
AbstractController#handlerRequest
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		// Delegate to WebContentGenerator for checking and preparing.
		checkAndPrepare(request, response, this instanceof LastModified);

		// Execute handleRequestInternal in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					return handleRequestInternal(request, response);
				}
			}
		}

		return handleRequestInternal(request, response);
	}

	/**
	 * Template method. Subclasses must implement this.
	 * The contract is the same as for {@code handleRequest}.
	 * @see #handleRequest
	 */
	protected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
	    throws Exception;


synchronized (mutex) {
return handleRequestInternal(request, response);
}


是否同步session执行,同一个登陆用户串行处理请求



MultiActionController#handleRequestInternal
@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		try {
			String methodName = this.methodNameResolver.getHandlerMethodName(request);
			return invokeNamedMethod(methodName, request, response);
		}
		catch (NoSuchRequestHandlingMethodException ex) {
			return handleNoSuchRequestHandlingMethod(ex, request, response);
		}
	}





参考:
SpringMVC源码剖析(三)- DispatcherServlet的初始化流程
http://www.voidcn.com/article/p-xmxipnkv-boz.html
分享到:
评论

相关推荐

    SpringMVC源码剖析(三)- DispatcherServlet的初始化流程1

    在SpringMVC中,`DispatcherServlet`继承自`HttpServletBean`,它本身并没有直接实现初始化逻辑,而是通过模板方法设计模式将具体初始化任务交给了子类`FrameworkServlet`。 `DispatcherServlet`的初始化入口是`...

    SpringMVC源码剖析(二)- DispatcherServlet的前世今生1

    实现配置元素的对象化,关键在于如何将Spring容器与Spring MVC的初始化过程结合。为此,Spring MVC引入了WebApplicationContext接口,特别是XmlWebApplicationContext,它是专门为Web应用程序设计的IoC上下文。它...

    官方原版源码 spring-framework-5.2.9.RELEASE.zip

    1. **设计模式实践**:Spring源码中大量运用了工厂模式、单例模式、观察者模式等设计模式,学习源码能加深对设计模式的理解。 2. **性能优化**:通过对源码的学习,开发者可以了解Spring如何进行性能优化,如缓存、...

    官方原版源码spring-framework-5.0.13.RELEASE.zip

    1. **初始化流程**:从`org.springframework.context.support.ClassPathXmlApplicationContext`或`org.springframework.web.context.ContextLoader`开始,理解如何加载配置并创建Bean定义。 2. **依赖注入**:研究`...

    spring-framework-4.3.0源代码

    通过分析源码,我们还可以了解到Spring如何优雅地实现设计模式,从而提升我们的设计能力。总之,SpringMVC的源代码是一个无价的学习工具,无论你是初学者还是经验丰富的开发者,都能从中受益匪浅。

    spring源码包.zip

    它解析XML或注解配置,创建Bean实例,管理Bean的依赖关系,执行初始化和销毁方法,以及实现Bean的单例或多例模式。 `spring-core`模块包含了Spring的基本工具类和基础设施,如Resource接口、ConversionService接口...

    官方原版源码spring-framework-5.0.12.RELEASE.zip

    1. Bean工厂(BeanFactory)与ApplicationContext:BeanFactory是Spring的核心,负责创建、初始化、配置和管理Bean。ApplicationContext在此基础上增加了对国际化、事件发布、资源加载等功能。 2. 依赖注入(DI):...

    官方源码 spring-framework-5.3.7.zip

    通过对Spring Framework 5.3.7的官方源码学习,开发者不仅能掌握框架的运行机制,还能了解到设计模式和最佳实践,从而在实际项目中发挥出Spring的强大威力。无论是新手还是资深开发者,深入源码都是提升技能的有效...

    官方原版源码spring-framework-5.1.1.RELEASE.zip

    本文将围绕Spring Framework的核心特性、设计模式以及源码中的关键组件进行详尽的探讨。 一、核心特性 1. **依赖注入(Dependency Injection,DI)**:Spring框架的基础,通过XML配置或注解方式实现对象间的依赖...

    spring-spring-framework-4.3.24.RELEASE.zip

    5. **Bean的生命周期**:Spring允许开发者定义bean的初始化和销毁方法,以及自定义的生命周期策略。在源码中,`org.springframework.beans.factory.config`包包含了许多关于生命周期的接口和类,如InitializingBean...

    spring-mvc-showcase-case1-client

    在初始化阶段,它会根据配置加载必要的库和应用模块,如AngularJS本身和其他依赖库。当需要加载新的视图或功能时,RequireJS会动态加载对应的JavaScript文件,确保应用的响应速度和用户体验。 整合过程中,需要注意...

    spring源码中英文注释

    通过深入研究这些源码和注释,开发者不仅可以提升自己的Spring框架技能,还能对Java编程有更深入的理解,尤其是在设计模式和面向接口编程方面。同时,这也有助于开发者在遇到问题时能够更快定位并解决。

    深入剖析Spring Web源码

    - `DispatcherServlet`初始化时会创建并配置一系列的`HandlerMapping`、`HandlerAdapter`和`ViewResolver`等组件。 - **3.1.3 根共享环境的加载** - 在`DispatcherServlet`初始化过程中,会加载一个或多个配置文件...

    spring-mvc-step-by-step(PDF)

    它基于MVC(Model-View-Controller)设计模式,使得开发者能够清晰地分离业务逻辑、数据处理和用户界面。本章节将详细介绍如何从零开始搭建一个Spring MVC应用。 ##### 1.1 创建项目目录结构 项目目录结构是任何...

    spring源码,java文件可直接看

    Spring框架是Java应用程序开发中的一个核心组件,尤其在企业级应用中被广泛使用。它以其模块化、松耦合的设计理念...对于Java开发者来说,研究Spring源码是一次宝贵的学习经历,有助于提高对设计模式和最佳实践的理解。

    开源框架面试题系列:Spring+SpringMVC+MyBatis-08.rar

    - **Bean管理**:Spring容器负责创建、配置、管理和初始化Bean。 - **IoC容器**:包括XML配置和注解配置两种方式,用于管理对象及其依赖关系。 - **Spring JDBC与数据访问**:提供模板类简化数据库操作,如...

    spring-framework-5.1.8.RELEASE:Spring源码包-源码包

    阅读Spring源码有助于提升对Java企业级应用开发的理解,加深对设计模式的掌握,同时也能为自定义扩展或优化现有应用提供思路。对于系统开源的标签,意味着开发者可以自由地研究、修改和分发Spring框架,进一步促进了...

    spring-framework-5.0.2.RELEASE-中文注释版-终极完美版.rar

    例如,`org.springframework.beans.factory.BeanFactory`接口定义了容器的基本操作,如获取Bean、初始化Bean等;`org.springframework.context.ApplicationContext`扩展了BeanFactory,提供了更多的企业级服务,如...

    spring mvc-spring boot-spring data

    2. **启动类**(通常包含@SpringBootApplication注解):这是Spring Boot应用的入口点,负责初始化并运行整个应用。 3. **Spring MVC控制器**:使用@Controller注解的Java类,处理HTTP请求并返回响应。 4. **Spring ...

    spring源码深入解析

    Spring作为Java领域最流行的开源框架之一,它的设计理念、实现方式以及源码背后的设计模式都对开发者有着极高的学习价值。通过深入理解Spring源码,开发者可以更好地掌握如何构建高效、可维护的Java应用。 1. **...

Global site tag (gtag.js) - Google Analytics