- 浏览: 50420 次
- 性别:
- 来自: 南京
文章分类
最新评论
springmvc的核心是DispatcherServlet
研究DispatcherServlet的设计分2个角度
1.DispatcherServlet的初始化
2.DispatcherServlet的访问
DispatcherServlet的初始化可以用模板方法设计模式概括
DispatcherServlet#init
将initServletBean设计为空方法,子类可以有选择的实现。
FrameworkServlet#initServletBean
DispatcherServlet#initStrategies
DispatcherServlet的访问可以通过模板方法,适配器设计模式概括
HttpSservlet#service
FrameworkServlet#doGet#processRequest
DispatcherServlet#doService
DispatcherServlet#doDispatch
通过适配器模式执行controller层实例
controller层执行常用适配器模式,如:
SimpleControllerHandlerAdapter 实现了Controller.
MultiActionController比直接实现Controller效率低,因为MultiActionController比单纯实现Controller的逻辑多,并且用到了反射,对于效率有要求的应尽量使用直接实现Controller
AnnotationMethodHandlerAdapter
SimpleServletHandlerAdapter 实现了Servlet
Controller层的设计采用了模板方法设计模式.父类AbstractController定义了算法的架构
AbstractController#handlerRequest
synchronized (mutex) {
return handleRequestInternal(request, response);
}
是否同步session执行,同一个登陆用户串行处理请求
MultiActionController#handleRequestInternal
参考:
SpringMVC源码剖析(三)- DispatcherServlet的初始化流程
http://www.voidcn.com/article/p-xmxipnkv-boz.html
研究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
发表评论
-
spring疑难解惑-循环依赖的解决
2020-06-17 23:27 542AbstractAutowireCapableBeanFact ... -
spring容器
2019-07-14 08:47 305private final ServletContainer ... -
spring容器
2019-07-13 23:35 0spring容器与springmvc容器 73 ... -
spring源码学习系列2.6-spring ioc原理-codes
2019-03-05 22:56 488web.xml <listener> < ... -
spring源码学习系列3.4-spring mvc原理-codes
2019-01-21 22:46 296本篇章从核心类角度解读springmvc的原理 web.xm ... -
spring源码学习系列4.2-spring aop原理-codes
2018-12-04 22:29 562jdk: Proxy InvocationHandler ... -
spring源码学习系列4.1-spring实现对ibatis的事务管理
2018-09-17 15:44 578事务由spring管理,可以理解为由spring管理数据库连接 ... -
spring源码学习系列4-3种常用的自动代理创建器
2018-09-02 15:48 5703种自动代理器是 AnnotationAwareAspectJ ... -
spring源码学习系列1.2-spring事务代理深入分析2
2018-05-27 19:46 452提示: BeanPostProcessor AopUtils ... -
spring源码学习系列2.5-ApplicationContext初始化-设计模式
2018-05-08 15:17 519ApplicationContext容器的初始化可以通过模板方 ... -
封装spring-security
2018-01-23 19:33 518github地址: https://github.com/ne ... -
eclipse导入spring源码
2018-05-12 07:20 980spring在git上的项目时gradle管理jar包的,所以 ... -
spring源码学习系列3.2.3-异常页面拦截机制
2017-07-29 19:07 768前序:本文的意义在于了解 tomcat处理异常 请求访问 ... -
spring源码学习系列3.2.2-How to bind String to Date
2017-07-17 12:40 598springmvc开发中,经常需将界面日期数据(String) ... -
spring源码学习系列3.2.1-command对象的绑定
2017-05-28 12:00 981在<spring源码学习系列3.2-handlerAda ... -
spring源码学习系列3.2-handlerAdapter执行
2017-05-28 12:01 409DispatcherServlet#doDispatch中调用 ... -
spring源码学习系列3.1-handlerMapping初始化
2017-05-28 11:56 701SimpleUrlHandlerMapping的继承体系 or ... -
spring源码学习系列2.4-finishRefresh会做什么
2017-05-06 16:36 578spring容器初始化完成后,调用finishRresh 该 ... -
spring源码学习系列3-springmvc原理
2017-05-28 11:56 457问题: springmvc是如何控 ... -
spring源码学习系列2-容器初始化入口-refresh
2017-04-23 21:33 477context=XmlWebApplicationContex ...
相关推荐
在SpringMVC中,`DispatcherServlet`继承自`HttpServletBean`,它本身并没有直接实现初始化逻辑,而是通过模板方法设计模式将具体初始化任务交给了子类`FrameworkServlet`。 `DispatcherServlet`的初始化入口是`...
实现配置元素的对象化,关键在于如何将Spring容器与Spring MVC的初始化过程结合。为此,Spring MVC引入了WebApplicationContext接口,特别是XmlWebApplicationContext,它是专门为Web应用程序设计的IoC上下文。它...
1. **设计模式实践**:Spring源码中大量运用了工厂模式、单例模式、观察者模式等设计模式,学习源码能加深对设计模式的理解。 2. **性能优化**:通过对源码的学习,开发者可以了解Spring如何进行性能优化,如缓存、...
1. **初始化流程**:从`org.springframework.context.support.ClassPathXmlApplicationContext`或`org.springframework.web.context.ContextLoader`开始,理解如何加载配置并创建Bean定义。 2. **依赖注入**:研究`...
通过分析源码,我们还可以了解到Spring如何优雅地实现设计模式,从而提升我们的设计能力。总之,SpringMVC的源代码是一个无价的学习工具,无论你是初学者还是经验丰富的开发者,都能从中受益匪浅。
它解析XML或注解配置,创建Bean实例,管理Bean的依赖关系,执行初始化和销毁方法,以及实现Bean的单例或多例模式。 `spring-core`模块包含了Spring的基本工具类和基础设施,如Resource接口、ConversionService接口...
1. Bean工厂(BeanFactory)与ApplicationContext:BeanFactory是Spring的核心,负责创建、初始化、配置和管理Bean。ApplicationContext在此基础上增加了对国际化、事件发布、资源加载等功能。 2. 依赖注入(DI):...
通过对Spring Framework 5.3.7的官方源码学习,开发者不仅能掌握框架的运行机制,还能了解到设计模式和最佳实践,从而在实际项目中发挥出Spring的强大威力。无论是新手还是资深开发者,深入源码都是提升技能的有效...
本文将围绕Spring Framework的核心特性、设计模式以及源码中的关键组件进行详尽的探讨。 一、核心特性 1. **依赖注入(Dependency Injection,DI)**:Spring框架的基础,通过XML配置或注解方式实现对象间的依赖...
5. **Bean的生命周期**:Spring允许开发者定义bean的初始化和销毁方法,以及自定义的生命周期策略。在源码中,`org.springframework.beans.factory.config`包包含了许多关于生命周期的接口和类,如InitializingBean...
在初始化阶段,它会根据配置加载必要的库和应用模块,如AngularJS本身和其他依赖库。当需要加载新的视图或功能时,RequireJS会动态加载对应的JavaScript文件,确保应用的响应速度和用户体验。 整合过程中,需要注意...
通过深入研究这些源码和注释,开发者不仅可以提升自己的Spring框架技能,还能对Java编程有更深入的理解,尤其是在设计模式和面向接口编程方面。同时,这也有助于开发者在遇到问题时能够更快定位并解决。
- `DispatcherServlet`初始化时会创建并配置一系列的`HandlerMapping`、`HandlerAdapter`和`ViewResolver`等组件。 - **3.1.3 根共享环境的加载** - 在`DispatcherServlet`初始化过程中,会加载一个或多个配置文件...
它基于MVC(Model-View-Controller)设计模式,使得开发者能够清晰地分离业务逻辑、数据处理和用户界面。本章节将详细介绍如何从零开始搭建一个Spring MVC应用。 ##### 1.1 创建项目目录结构 项目目录结构是任何...
Spring框架是Java应用程序开发中的一个核心组件,尤其在企业级应用中被广泛使用。它以其模块化、松耦合的设计理念...对于Java开发者来说,研究Spring源码是一次宝贵的学习经历,有助于提高对设计模式和最佳实践的理解。
- **Bean管理**:Spring容器负责创建、配置、管理和初始化Bean。 - **IoC容器**:包括XML配置和注解配置两种方式,用于管理对象及其依赖关系。 - **Spring JDBC与数据访问**:提供模板类简化数据库操作,如...
阅读Spring源码有助于提升对Java企业级应用开发的理解,加深对设计模式的掌握,同时也能为自定义扩展或优化现有应用提供思路。对于系统开源的标签,意味着开发者可以自由地研究、修改和分发Spring框架,进一步促进了...
例如,`org.springframework.beans.factory.BeanFactory`接口定义了容器的基本操作,如获取Bean、初始化Bean等;`org.springframework.context.ApplicationContext`扩展了BeanFactory,提供了更多的企业级服务,如...
2. **启动类**(通常包含@SpringBootApplication注解):这是Spring Boot应用的入口点,负责初始化并运行整个应用。 3. **Spring MVC控制器**:使用@Controller注解的Java类,处理HTTP请求并返回响应。 4. **Spring ...
Spring作为Java领域最流行的开源框架之一,它的设计理念、实现方式以及源码背后的设计模式都对开发者有着极高的学习价值。通过深入理解Spring源码,开发者可以更好地掌握如何构建高效、可维护的Java应用。 1. **...