- 浏览: 50840 次
- 性别:
- 来自: 南京
文章分类
最新评论
问题:
springmvc是如何控制浏览器显示与返回的modelAndView是一致的,而不是一个用户请求的数据返回给了另一个人?
response中存有客户端的信息
分析DispatcherServlet调用效率
springmvc应用大量缓存来提高其工作效率
springmvc的分发器设计的借鉴意义?
一些特殊url不走springmvc,需单独设计servlet,可以借鉴spring是如何封装请求的,要做哪些处理
controller可以应用aop吗,拦截器与aop有什么区别和相同之处?
spring版本3.2.2
核心接口:
DispatcherServlet
HandlerExecutionChain
HandlerAdapter
1.springmvc启动入口
GenericServlet#init(ServletConfig config)->httpServletBean#init
2.springmvc访问入口
HttpServlet#service->FrameworkServlet#&doGet&doPost->FrameworkServlet#processRequest->DispatcherServlet#doService->DispatcherServlet#doDispatch
1.springmvc启动入口
首先在项目web.xml中配置,springmvc的servlet
注意:这里<url-pattern>应该配置/,表示其他默认servlet没有找到的路径都交由DispatcherServlet处理。如果配置成了/*,那么会拦截所有请求包括.jsp,.js,.css等,访问.jsp时由于找不到默认的handler将无法访问页面。
讲到其他默认servlet找不到的路径,由DispatcherServlet处理,那么有哪些默认servlet呢,到TOMCAT_HOME/conf/web.xml下,
其实DispatcherServlet覆盖的就是default,而jsp servlet拦截了.jsp后缀的访问路径
学习springmvc的过程中,意识到访问.jsp时,不走DispatcherServlet,不觉对.jsp的访问入口感到好奇,进而了解了到相关的知识点。
Class DispatcherServlet
java.lang.Object
javax.servlet.GenericServlet
javax.servlet.http.HttpServlet
org.springframework.web.servlet.HttpServletBean
org.springframework.web.servlet.FrameworkServlet
org.springframework.web.servlet.DispatcherServlet
All Implemented Interfaces:
Serializable, Servlet, ServletConfig, Aware, ApplicationContextAware, EnvironmentAware, EnvironmentCapable
DispatcherServlet本质上是servlet,根据servlet生命周期,首先会执行init方法
httpServletBean#init
//初始化web环境
FrameworkServlet#initServletBean
FrameworkServlet#initWebApplicationContext
FrameworkServlet#createWebApplicationContext
FrameworkServlet#createWebApplicationContext
扩展-自定义WebApplicationContext
FrameworkServlet#configureAndRefreshWebApplicationContext
创建容器
====================================职责分界线==============================
在容器中初始化springmvc信息
XmlWebApplicationContext#refresh
DispatcherServlet#doService
对于这些父子类分工合作的类而言,最终子类总是实现最核心的部分,而其父类则很多是一些环境准备或初始化工作。用户可以自定义这些子类,沿用相似的自定义继承架构
监听器回调-初始化springmvc信息-springmvc核心
DispatcherServlet#onRefresh
2.springmvc访问入口
以doPost为例
FrameworkServlet#doPost
FrameworkServlet#processRequest
DispatcherServlet#doService
DispatcherServlet#doDispatch
DispatcherServlet#getHandler
AbstractHandlerMapping#getHandler
AbstractHandlerMapping#getHandlerExecutionChain-执行链中添加自定义拦截器
参考:
Spring IOC BeanWrapper
http://www.infocool.net/kb/Other/201611/227714.html
Spring IOC BeanWrapper
http://blog.csdn.net/u012410733/article/details/53346345
SpringMVC源码剖析(一)- 从抽象和接口说起
https://my.oschina.net/lichhao/blog/99039?p=2&temp=1494051282915#blog-comments-list
WEB请求处理五:MVC框架请求处理
http://www.jianshu.com/p/6462e69ce241
困惑:谁能帮我解答一个关于BeanWrapperImpl设计的问题
http://stamen.iteye.com/blog/43048
你真的了解DispatcherServlet的url-pattern配置吗?
http://www.itwendao.com/article/detail/382888.html
SpingMVC第一个拦截器未执行BUG分析
http://uuhorse.iteye.com/blog/2311494
http://www.cnblogs.com/gkaigk1987/articles/5466052.html
handlerAdapter
http://www.cnblogs.com/wade-luffy/p/6085172.html
http://www.cnblogs.com/JemBai/archive/2010/01/07/1641048.html
http://blog.csdn.net/u012420654/article/details/58687790
springmvc是如何控制浏览器显示与返回的modelAndView是一致的,而不是一个用户请求的数据返回给了另一个人?
response中存有客户端的信息
分析DispatcherServlet调用效率
springmvc应用大量缓存来提高其工作效率
springmvc的分发器设计的借鉴意义?
一些特殊url不走springmvc,需单独设计servlet,可以借鉴spring是如何封装请求的,要做哪些处理
controller可以应用aop吗,拦截器与aop有什么区别和相同之处?
spring版本3.2.2
核心接口:
DispatcherServlet
HandlerExecutionChain
HandlerAdapter
1.springmvc启动入口
GenericServlet#init(ServletConfig config)->httpServletBean#init
2.springmvc访问入口
HttpServlet#service->FrameworkServlet#&doGet&doPost->FrameworkServlet#processRequest->DispatcherServlet#doService->DispatcherServlet#doDispatch
1.springmvc启动入口
首先在项目web.xml中配置,springmvc的servlet
<servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring-mvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
注意:这里<url-pattern>应该配置/,表示其他默认servlet没有找到的路径都交由DispatcherServlet处理。如果配置成了/*,那么会拦截所有请求包括.jsp,.js,.css等,访问.jsp时由于找不到默认的handler将无法访问页面。
讲到其他默认servlet找不到的路径,由DispatcherServlet处理,那么有哪些默认servlet呢,到TOMCAT_HOME/conf/web.xml下,
<!-- The mapping for the default servlet --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- The mappings for the JSP servlet --> <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> <url-pattern>*.jspx</url-pattern> </servlet-mapping>
其实DispatcherServlet覆盖的就是default,而jsp servlet拦截了.jsp后缀的访问路径
学习springmvc的过程中,意识到访问.jsp时,不走DispatcherServlet,不觉对.jsp的访问入口感到好奇,进而了解了到相关的知识点。
Class DispatcherServlet
java.lang.Object
javax.servlet.GenericServlet
javax.servlet.http.HttpServlet
org.springframework.web.servlet.HttpServletBean
org.springframework.web.servlet.FrameworkServlet
org.springframework.web.servlet.DispatcherServlet
All Implemented Interfaces:
Serializable, Servlet, ServletConfig, Aware, ApplicationContextAware, EnvironmentAware, EnvironmentCapable
DispatcherServlet本质上是servlet,根据servlet生命周期,首先会执行init方法
httpServletBean#init
/** * Map config parameters onto bean properties of this servlet, and * invoke subclass initialization. * @throws ServletException if bean properties are invalid (or required * properties are missing), or if subclass initialization fails. */ @Override public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } // Set bean properties from init parameters. try { //获取属性,web.xml配置的init-param。spring中一般通过beanWrapper设置属性,BeanWrapper封装了实例的反射方法 PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); //注册属性编辑器,如contextConfigLocation。目标对象是Resource可以直接在xml定义这个Resource为String类型 //DispatcherServlet中并没有定义为Resource类型的属性,所以这里也就用不到这个属性编辑器 bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); //初始化属性 bw.setPropertyValues(pvs, true); } catch (BeansException ex) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); throw ex; } //初始化web环境 // Let subclasses do whatever initialization they like. initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } }
//初始化web环境
FrameworkServlet#initServletBean
/** * Overridden method of {@link HttpServletBean}, invoked after any bean properties * have been set. Creates this servlet's WebApplicationContext. */ @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 { //1 创建servletContext上下文环境 this.webApplicationContext = initWebApplicationContext(); //2 提供给子类初始化的扩展点 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"); } }
FrameworkServlet#initWebApplicationContext
protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it 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) { // No context instance was injected at construction time -> see if one // has been registered in the servlet context. If one exists, it is assumed // that the parent context (if any) has already been set and that the // user has performed any initialization such as setting the context id //根据属性contextAttr返回context,若未设置contextAttr为空,返回空 wac = findWebApplicationContext(); } if (wac == null) { // No context instance is defined for this servlet -> create a local one //1.1 创建并初始化servletContext(XmlWebApplicationContext) 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; }
FrameworkServlet#createWebApplicationContext
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { return createWebApplicationContext((ApplicationContext) parent); }
FrameworkServlet#createWebApplicationContext
/** * Instantiate the WebApplicationContext for this servlet, either a default * {@link org.springframework.web.context.support.XmlWebApplicationContext} * or a {@link #setContextClass custom context class}, if set. * <p>This implementation expects custom contexts to implement the * {@link org.springframework.web.context.ConfigurableWebApplicationContext} * interface. Can be overridden in subclasses. * <p>Do not forget to register this servlet instance as application listener on the * created context (for triggering its {@link #onRefresh callback}, and to call * {@link org.springframework.context.ConfigurableApplicationContext#refresh()} * before returning the context instance. * @param parent the parent ApplicationContext to use, or {@code null} if none * @return the WebApplicationContext for this servlet * @see org.springframework.web.context.support.XmlWebApplicationContext */ protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { // 1.1.1 实例化容器类XmlWebApplicationContext // 扩展-可以自定义WebApplicationContext,默认是XmlWebApplication Class<?> contextClass = getContextClass(); if (this.logger.isDebugEnabled()) { this.logger.debug("Servlet with name '" + getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]"); } if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException( "Fatal initialization error in servlet with name '" + getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext"); } ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); // 1.1.2 初始化容器类XmlWebApplicationContext wac.setEnvironment(getEnvironment()); wac.setParent(parent); wac.setConfigLocation(getContextConfigLocation()); configureAndRefreshWebApplicationContext(wac); return wac; }
扩展-自定义WebApplicationContext
FrameworkServlet#configureAndRefreshWebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information if (this.contextId != null) { wac.setId(this.contextId); } else { // Generate default id... ServletContext sc = getServletContext(); if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { // Servlet <= 2.4: resort to name specified in web.xml, if any. String servletContextName = sc.getServletContextName(); if (servletContextName != null) { wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName + "." + getServletName()); } else { wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + getServletName()); } } else { // Servlet 2.5's getContextPath available! wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()) + "/" + getServletName()); } } } wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); //定义并注册applicationListener,context初始化结束时调用。以便回调FrameworkServlet#onRefresh wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); // The wac environment's #initPropertySources will be called in any case when the context // is refreshed; do it eagerly here to ensure servlet property sources are in place for // use in any post-processing or initialization that occurs below prior to #refresh ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig()); } postProcessWebApplicationContext(wac); //扩展-servlet设置参数globalInitializerClasses,调用ApplicationContextInitializer#initialize applyInitializers(wac); //解析并初始化配置文件(如:spring-servlet.xml)中的配置 //具体见:http://newjava-sina-cn.iteye.com/blog/2369741 wac.refresh(); }
创建容器
====================================职责分界线==============================
在容器中初始化springmvc信息
XmlWebApplicationContext#refresh
DispatcherServlet#doService
对于这些父子类分工合作的类而言,最终子类总是实现最核心的部分,而其父类则很多是一些环境准备或初始化工作。用户可以自定义这些子类,沿用相似的自定义继承架构
监听器回调-初始化springmvc信息-springmvc核心
DispatcherServlet#onRefresh
/** * This implementation calls {@link #initStrategies}. */ @Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } /** * Initialize the strategy objects that this servlet uses. * <p>May be overridden in subclasses in order to initialize further strategy objects. */ protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); //初始化映射处理器 handlerMappings initHandlerMappings(context); //初始化适配器处理器 initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); //初始化视图解析器 viewResolvers initViewResolvers(context); initFlashMapManager(context); }
2.springmvc访问入口
以doPost为例
FrameworkServlet#doPost
/** * Delegate POST requests to {@link #processRequest}. * @see #doService */ @Override protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1 http请求统一转给processRequest处理 processRequest(request, response); }
FrameworkServlet#processRequest
/** * Process this request, publishing an event regardless of the outcome. * <p>The actual event handling is performed by the abstract * {@link #doService} template method. */ protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; //1.1 绑定请求信息到当前线程 //创建localeContext LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); // zh_CN LocaleContext localeContext = buildLocaleContext(request); //创建requestAttributes RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); //Spring 中的WebAsyncManager 有什么应用场景? //https://segmentfault.com/q/1010000009403867/a-1020000009411777 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); //将请求信息绑定到当前线程 initContextHolders(request, localeContext, requestAttributes); try { //1.2 处理请求信息 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
//由中文注释可知,设置特殊的request attributes并代理doDispatch处理 /** * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch} * for the actual dispatching. */ @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) + "]"); } //如父jsp页面包含<jsp:include page="${basePath}login.do?method=getIncludePage"></jsp:include>。父页面请求login.do?method=getIncludePage路径时,则属性中包含javax.servlet.include.request_uri等include页面信息的相关属性 // 缓存这些include页面相关属性,防止处理器改变这些信息。在处理器处理完成后,如果属性值发生变化则恢复restoreAttributesAfterInclude(request, attributesSnapshot); // 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()); // spring mvc支持页面显示的国际化配置 //涉及的spring元素:<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> //ResourceBundleMessageSource CookieLocaleResolver //<spring:message code=""/> <fmt:message key="" /> //参考:http://blog.lifw.org/post/26098052 request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); // spring mvc支持主题 //涉及的spring元素:<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> //ResourceBundleThemeSource,SessionThemeResolver //<spring:theme code=''/> request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); //获取前一次request中设置的flashAttribute //https://t.hao0.me/spring/2016/01/15/spring-flash-map.html FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } //将值保存到request中。这样就不需要通过浏览器跳转组装链接来传递参数了 //如: //1-flashAttribute //redirectAttributes.addFlashAttribute("message", "Submit successfully!"); //redirect:url //2-没有flashAttribute //redirect:url+"?" + successMsg= request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { //springmvc转发请求的核心方法 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); //1 获取执行请求的链HandlerExecutionChain(包括controller和拦截器) // 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. //2 获取执行handler的适配器 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; } } //3 执行拦截器的preHandle,如:未登录直接返回 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //4 执行用户定义的业务逻辑 // 见<spring源码学习系列3.2-handlerAdapter执行> // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(request, mv); //5 执行拦截器的postHandle 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); } } } }
DispatcherServlet#getHandler
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() + "'"); } //1.1 委托handlerMapping获取HandlerExecutionChain HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //1.1.1 获取默认HandlerExecutionChain(包括controller和默认interceptor) Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } //1.1.2 springmvc扩展点-HandlerExecutionChain添加其他自定义的interceoptor return getHandlerExecutionChain(handler, request); }
AbstractHandlerMapping#getHandlerExecutionChain-执行链中添加自定义拦截器
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); //1.1.2.1 abstractHandlerMapping.adaptedInterceptors属性 //abstractHandlerMapping.interceptoers转化而来,见<spring源码学习系列3.1-handlerMapping初始化> chain.addInterceptors(getAdaptedInterceptors()); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); //1.1.2.2 abstractHandlerMapping.mappedInterceptor属性 //<mvc:interceptor/>和abstractHandlerMapping.interceptoers转化而来 for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) { if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } return chain; }
参考:
Spring IOC BeanWrapper
http://www.infocool.net/kb/Other/201611/227714.html
Spring IOC BeanWrapper
http://blog.csdn.net/u012410733/article/details/53346345
SpringMVC源码剖析(一)- 从抽象和接口说起
https://my.oschina.net/lichhao/blog/99039?p=2&temp=1494051282915#blog-comments-list
WEB请求处理五:MVC框架请求处理
http://www.jianshu.com/p/6462e69ce241
困惑:谁能帮我解答一个关于BeanWrapperImpl设计的问题
http://stamen.iteye.com/blog/43048
你真的了解DispatcherServlet的url-pattern配置吗?
http://www.itwendao.com/article/detail/382888.html
SpingMVC第一个拦截器未执行BUG分析
http://uuhorse.iteye.com/blog/2311494
http://www.cnblogs.com/gkaigk1987/articles/5466052.html
handlerAdapter
http://www.cnblogs.com/wade-luffy/p/6085172.html
http://www.cnblogs.com/JemBai/archive/2010/01/07/1641048.html
http://blog.csdn.net/u012420654/article/details/58687790
发表评论
-
spring疑难解惑-循环依赖的解决
2020-06-17 23:27 554AbstractAutowireCapableBeanFact ... -
spring容器
2019-07-14 08:47 308private final ServletContainer ... -
spring容器
2019-07-13 23:35 0spring容器与springmvc容器 73 ... -
spring源码学习系列2.6-spring ioc原理-codes
2019-03-05 22:56 491web.xml <listener> < ... -
spring源码学习系列3.4-spring mvc原理-codes
2019-01-21 22:46 302本篇章从核心类角度解读springmvc的原理 web.xm ... -
spring源码学习系列4.2-spring aop原理-codes
2018-12-04 22:29 566jdk: Proxy InvocationHandler ... -
spring源码学习系列4.1-spring实现对ibatis的事务管理
2018-09-17 15:44 585事务由spring管理,可以理解为由spring管理数据库连接 ... -
spring源码学习系列4-3种常用的自动代理创建器
2018-09-02 15:48 5773种自动代理器是 AnnotationAwareAspectJ ... -
spring源码学习系列1.2-spring事务代理深入分析2
2018-05-27 19:46 457提示: BeanPostProcessor AopUtils ... -
spring源码学习系列2.5-ApplicationContext初始化-设计模式
2018-05-08 15:17 527ApplicationContext容器的初始化可以通过模板方 ... -
spring源码学习系列3.3-DispatcherServlet初始化-设计模式
2018-05-07 11:12 630springmvc的核心是DispatcherServlet ... -
封装spring-security
2018-01-23 19:33 523github地址: https://github.com/ne ... -
eclipse导入spring源码
2018-05-12 07:20 985spring在git上的项目时gradle管理jar包的,所以 ... -
spring源码学习系列3.2.3-异常页面拦截机制
2017-07-29 19:07 777前序:本文的意义在于了解 tomcat处理异常 请求访问 ... -
spring源码学习系列3.2.2-How to bind String to Date
2017-07-17 12:40 604springmvc开发中,经常需将界面日期数据(String) ... -
spring源码学习系列3.2.1-command对象的绑定
2017-05-28 12:00 994在<spring源码学习系列3.2-handlerAda ... -
spring源码学习系列3.2-handlerAdapter执行
2017-05-28 12:01 414DispatcherServlet#doDispatch中调用 ... -
spring源码学习系列3.1-handlerMapping初始化
2017-05-28 11:56 706SimpleUrlHandlerMapping的继承体系 or ... -
spring源码学习系列2.4-finishRefresh会做什么
2017-05-06 16:36 584spring容器初始化完成后,调用finishRresh 该 ... -
spring源码学习系列2-容器初始化入口-refresh
2017-04-23 21:33 480context=XmlWebApplicationContex ...
相关推荐
通过源码,开发者可以深入理解库的工作原理,以及如何自定义和扩展其功能。 6. **核心组件**:Swagger-SpringMVC的核心组件包括`@Api`注解,用于标记API资源;`@ApiOperation`用于描述控制器方法;`@ApiParam`用于...
通过深入学习和理解SpringMVC和Hibernate4的原理和使用,开发者可以更好地掌握这个工作日报系统的实现细节,并能在此基础上进行定制和优化,以满足特定企业的管理需求。在实际工作中,这样的系统不仅有助于提高工作...
Spring MVC、Spring 和 Hibernate 是Java开发中常用的三大框架,它们分别负责不同的职责:Spring MVC用于构建Web应用程序的...通过学习这个项目,开发者可以深入了解这些框架的协同工作原理,提升自己的Web开发技能。
同时,对SpringMVC的请求处理流程、Spring的DI和AOP原理、Mybatis的SQL映射机制有深入理解,为今后的项目开发打下坚实基础。对于源码探索和工具使用,读者可以进一步研究这些框架的内部实现,以便更好地优化和扩展...
总的来说,"Mybatis-SpringMVC在线考试系统源码"是一个实用的学习资源,无论是对SSM框架的实践,还是对在线考试系统的设计与开发,都能提供有价值的参考。通过深入研究和实践,可以提升Java Web开发能力。
这个源代码库提供了深入理解SpringMVC工作原理的机会,这对于开发者来说是一个宝贵的学习资源。 在SpringMVC中,主要涉及以下几个核心概念: 1. **DispatcherServlet**:这是SpringMVC的前端控制器,负责接收HTTP...
02-手写模拟Spring底层原理-周瑜 03-Spring之底层架构核心概念解析-周瑜 04-Spring之Bean生命周期源码解析上-周瑜 05-Spring之Bean生命周期源码解析下-周瑜 06-Spring之依赖注入源码解析(上)-周瑜 07-Spring之依赖...
《Spring源码合集:揭示Java后端开发的基石》 Spring框架作为Java后端开发的核心,其源码的研究对于提升开发者对系统架构理解和优化能力至关重要。本合集深入剖析了Spring的诸多关键特性,包括依赖注入、配置类解析...
在学习过程中,你可以逐步理解 Spring MVC 的组件和工作原理,掌握如何使用 Hibernate 进行数据库操作,并最终通过实际项目来巩固所学知识。这个压缩包是初学者宝贵的参考资料,有助于快速入门 Java Web 开发。
在源码学习过程中,你可能会遇到以下关键类和接口:`RequestMappingHandlerMapping`, `RequestMappingHandlerAdapter`, `SimpleControllerHandlerAdapter`, `ModelAndView`, `DefaultListableBeanFactory`, `Bean...
在Spring MVC中,`@RequestBody` 注解用于接收HTTP请求体中的JSON或其他格式的数据,并将其自动绑定到控制器...同时,理解Spring MVC中消息转换器的工作原理和配置方式,有助于更好地优化和调试与数据绑定相关的错误。
最后,深入理解Spring源码不仅可以帮助你解决实际开发中的问题,还能让你更好地掌握Java企业级应用的开发技巧,为你的职业生涯增色添彩。因此,花时间研究这个源码jar包是非常值得的投资。祝你在学习Spring的道路...
《SSM框架详解:基于spring-mybatis-spring...总结,"spring-mybatis-spring-1.3.2.tar.gz"是一个典型的SSM框架示例,通过学习和实践,我们可以掌握SSM框架的核心原理和使用技巧,为开发复杂的企业级应用打下坚实基础。
本文将深入探讨一款基于SpringMVC框架的高级图书管理系统后台源码,以及配套的数据库脚本,帮助读者理解其工作原理并进行实际操作。 首先,让我们来看看运行环境。这个系统依赖于Java编程语言,这意味着你需要在...
在标题中提到的"Spring源码学习附注释(Version 4.2.0)",这部分内容指的是Spring框架的核心源代码,版本为4.2.0。源码学习对于深入理解Spring的工作原理和扩展自定义功能至关重要。注释的加入使得源码更易于阅读和...
本文将深入探讨Spring、SpringMVC和SpringBoot的源码,帮助你理解和掌握这三大框架的关键知识点,从而在金三银四的Java面试中脱颖而出。 首先,让我们从Spring框架开始。Spring的核心是依赖注入(Dependency ...
### Spring核心源码解读与手动实现SpringMVC #### 一、Spring框架简介 Spring框架是由Rod Johnson在2004年发起的一个开源项目,它是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器。Spring框架的核心特性包括:...
5. **源码分析**:对于"Spring4+SpringMVC4+Hibernate4整合源码",研究这些源码可以帮助开发者深入理解三大框架的内部工作原理,学习如何配置和使用它们进行实际项目开发。通过源码,你可以看到如何配置Spring的...
这份"Spring学习笔记+学习源码.zip"资源包含了深入学习Spring及其相关技术的知识点,以及实践代码,对提升Spring技能将大有裨益。 首先,我们来详细讨论Spring框架的主要组件和功能: 1. **依赖注入(Dependency ...
在这个"First springMVC示例.rar"中,我们找到了一个适合初学者的入门教程,它包括源码和文档,帮助理解Spring MVC的基本概念和工作原理。 首先,让我们深入了解一下Spring MVC的核心概念。Spring MVC是Spring框架...