首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

Spirng 源代码学习笔记 Web 篇(1)DispatcherServlet

2014-01-08 
Spirng 源代码学习笔记 Web 篇(一)DispatcherServlet图中的 Front controller 指的就是?org.springframewo

Spirng 源代码学习笔记 Web 篇(一)DispatcherServlet

图中的 Front controller 指的就是

?

org.springframework.web.servlet.DispatcherServlet

?DispatcherServlet 是请求的唯一入口,控制着 MVC 的整个流程。

?

?一个 http 请求被?DispatcherServlet?拦截时,首先,根据 http 方法会映射到父类?FrameworkServlet?对应的?doGet、doPost、doPut 等方法上,最后都会转到?processRequest 方法,

然后调用?DispatcherServlet? 的?doService 方法:

?

?

/** * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch} * for the actual dispatching. */@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) {String requestUri = urlPathHelper.getRequestUri(request);logger.debug("DispatcherServlet with name '" + getServletName() + "' 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());try {doDispatch(request, response);}finally {// Restore the original attribute snapshot, in case of an include.if (attributesSnapshot != null) {restoreAttributesAfterInclude(request, attributesSnapshot);}}}
?

?该方法绑定部分常用信息到当前线程,便于在后续处理中共享信息。然后调用?doDispatch 方法

?

/** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;int interceptorIndex = -1;try {ModelAndView mv;boolean errorView = false;try {processedRequest = checkMultipart(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()) {String requestUri = urlPathHelper.getRequestUri(request);logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}// Apply preHandle methods of registered interceptors.HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();if (interceptors != null) {for (int i = 0; i < interceptors.length; i++) {HandlerInterceptor interceptor = interceptors[i];if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);return;}interceptorIndex = i;}}// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// Do we need view name translation?if (mv != null && !mv.hasView()) {mv.setViewName(getDefaultViewName(request));}// Apply postHandle methods of registered interceptors.if (interceptors != null) {for (int i = interceptors.length - 1; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);}}}catch (ModelAndViewDefiningException ex) {logger.debug("ModelAndViewDefiningException encountered", ex);mv = ex.getModelAndView();}catch (Exception ex) {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(processedRequest, response, handler, ex);errorView = (mv != null);}// Did the handler return a view to render?if (mv != null && !mv.wasCleared()) {render(mv, processedRequest, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}else {if (logger.isDebugEnabled()) {logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +"': assuming HandlerAdapter completed request handling");}}// Trigger after-completion for successful outcome.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);}catch (Exception ex) {// Trigger after-completion for thrown exception.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);throw ex;}catch (Error err) {ServletException ex = new NestedServletException("Handler processing failed", err);// Trigger after-completion for thrown exception.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);throw ex;}finally {// Clean up any resources used by a multipart request.if (processedRequest != request) {cleanupMultipart(processedRequest);}}}
?

? ? ?getHandler 根据请求 以及 handlerMapping 映射到实际的处理类(即 Controller),找到对应的?HandlerAdapter 。

? ? ?如果存在?HandlerInterceptor ,则在调用实际处理类前,调用 preHandler方法;在完成后,调用 postHandler。

? ? ?调用实际 Controller 后,返回的视图一般只是视图的名称。viewResolve 会根据名称解析实际的视图对象,然后调用视图对象的 render 方法进行实际的视图渲染。这样,视图的解析、渲染过程和请求的处理过程就分开了,互不影响。

?

DispatcherServlet?初始化

?

DispatcherServlet 是定义在 web.xml 中的 Servlet ,在服务器启动时调用父类?HttpServletBean??的 init() 方法开始初始化。

?

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));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");}}

?

?

首先,设置 Servlet 配置,然后调用?FrameworkServlet 的?initServletBean() ,initServletBean()中调用?initWebApplicationContext ()?创建?Spring 应用上下文?,

?

protected WebApplicationContext initWebApplicationContext() {WebApplicationContext wac = findWebApplicationContext();if (wac == null) {// No fixed context defined for this servlet - create a local one.WebApplicationContext parent =WebApplicationContextUtils.getWebApplicationContext(getServletContext());wac = createWebApplicationContext(parent);}if (!this.refreshEventReceived) {// Apparently not a ConfigurableApplicationContext with refresh support:// triggering 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;}

创建完成后调用?DispatcherServlet?的?onRefresh(wac)?方法进行?DispatcherServlet?的初始化工作。

??

/** * This implementation calls {@link #initStrategies}. */@Overrideprotected 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);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);}

?

初始化中的每个方法负责初始化一个类型的组件,这些组件用户都可以自定义。当没有自定义时,自动根据?DispatcherServlet.properties 文件中配置的类型进行初始化。配置多个的,说明该项组件可以是一个集合。

?

?

# Default implementation classes for DispatcherServlet's strategy interfaces.# Used as fallback when no matching beans are found in the DispatcherServlet context.# Not meant to be customized by application developers.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.InternalResourceViewResolver
?

?

默认的?HandlerMapping 为根据 url 映射为 Controller 的 BeanName,以及注解解析类;注解解析类在创建时会解析 spring 上下文中所有的类,解析类或方法上标注的 @RequestMapping,以后将其中的 url 都映射为对应的 Handler。?

?

默认的视图解析类为 jsp 解析类。

?

至此,DispatcherServlet?的初始化工作完成。

?

热点排行