`
ayufox
  • 浏览: 273746 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

SpringMVC源码解析(上)

阅读更多

1.从DispatcherServlet开始
     与很多使用广泛的MVC框架一样,SpringMVC使用的是FrontController模式,所有的设计都围绕DispatcherServlet为中心来展开的。见下图,所有请求从DispatcherServlet进入,DispatcherServlet根据配置好的映射策略确定处理的Controller,Controller处理完成返回ModelAndView,DispatcherServlet根据配置好的视图策略确定处理的View,由View生成具体的视图返回给请求客户端。


2.初始化
    SpringMVC几个核心的配置策略包括:
    *HandlerMapping:请求-处理器映射策略处理,根据请求生成具体的处理链对象
    *HandlerAdapter:处理器适配器,由于最终的Handler对象不一定是一个标准接口的实现对象,参数也可能非常的灵活复杂,因此所有的对象需要一个合适的适配器适配成标准的处理接口来最终执行请求
    *ViewResolver:视图映射策略,根据视图名称和请求情况,最终映射到具体的处理View,由View对象来生成具体的视图。
    其他的配置策略包括MultipartResolver、LocaleResolver、ThemeResolver等等,但并不影响我们对整个SpringMVC的工作原理的理解,此处并不具体说明。
1)初始化Context
     见下图DispatcherServlet的继承结构,其中,HttpServletBean主要功能是在初始化(init)时将servlet的配置参数(init-param)转换成Servlet的属性,FrameworkServlet主要功能是与ApplicationContext的集成,因此Context的初始化工作主要在FrameworkServlet中进行。

   
     Context初始化的过程可以通过如下过程来描述:HttServletBean.init --> FrameworkServlet.initServletBean --> FrameworkServlet.initWebApplicationContext。具体的初始化过程可见如下代码: 

     FrameworkServlet.initWebApplicationContext

	protected WebApplicationContext initWebApplicationContext() throws BeansException {
		WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext 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 (logger.isDebugEnabled()) {
				logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}

		return wac;
	}

     FrameworkServlet.createWebApplicationContext

	protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)
			throws BeansException {

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet with name '" + getServletName() +
					"' will try to create custom WebApplicationContext context of class '" +
					getContextClass().getName() + "'" + ", using parent context [" + parent + "]");
		}
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(getContextClass())) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + getContextClass().getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}

		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());
		wac.setParent(parent);
		wac.setServletContext(getServletContext());
		wac.setServletConfig(getServletConfig());
		wac.setNamespace(getNamespace());
		wac.setConfigLocation(getContextConfigLocation());
		wac.addApplicationListener(new SourceFilteringListener(wac, this));

		postProcessWebApplicationContext(wac);
		wac.refresh();

		return wac;
	}
 

2)初始化策略
   具体与SpringMVC相关的策略在DispatcherServlet中初始化,DispatcherServlet的类定义被加载时,如下初始化代码段被执行:

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

 

   我们可以看到,SpringMVC的策略在与DispatcherServlet同目录的Dispatcher.properties文件中配置,如下是Spring2.5的默认配置策略

 

Dispatcher.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.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.throwaway.ThrowawayControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

    当然,我们可以变更其处理策略,通过上面部分,我们知道,FrameworkServlet实现了ApplicationListener,并在构建WebApplicationContext后,将自身(this)向WebApplicationContext注册,因此WebApplicationContext初始化完毕之后,将发送ContextRefreshedEvent事件,该事件实际上被DispatcherServlet处理,处理过程如下:

    FrameworkServlet.onApplicationEvent --> DispatcherServlet.onRefresh --> DispatcherServlet.initStrategies

    DispatcherServlet.initStrategies代码如下,具体处理过程可参见Spring源代码

 

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

3.请求处理流程

    SpringMVC的请求处理从doService-->doDispatch为入口,实际上,我们只要紧紧抓住HandlerMapping、HandlerAdapter、ViewResolver这三个核心对象,SpringMVC的一整个运行机制看起来将非常简单,其主要处理流程包括:

1)将请求映射到具体的执行处理链,见如下代码

 

                               // Determine handler for the current request.
				mappedHandler = getHandler(processedRequest, false);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

   具体看一下getHandler是如何处理的

 

		protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
		HandlerExecutionChain handler =
				(HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
		if (handler != null) {
			if (!cache) {
				request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
			}
			return handler;
		}

		Iterator it = this.handlerMappings.iterator();
		while (it.hasNext()) {
			HandlerMapping hm = (HandlerMapping) it.next();
			if (logger.isDebugEnabled()) {
				logger.debug("Testing handler map [" + hm  + "] in DispatcherServlet with name '" +
						getServletName() + "'");
			}
			handler = hm.getHandler(request);
			if (handler != null) {
				if (cache) {
					request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);
				}
				return handler;
			}
		}
		return null;
	}

   可以看到,仅仅是遍历每一个HandlerMapping,如果能够其能够处理,则返回执行处理链(HandleExecuteChain)

2)执行处理链的拦截器列表的preHandle方法,如果执行时返回false,表示该拦截器已处理完请求要求停止执行后续的工作,则倒序执行所有已执行过的拦截器的afterCompletion方法,并返回

 

				// 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;
					}
				}

 3)根据处理对象获得处理器适配器(HandlerAdapter),并由处理适配器负责最终的请求处理,并返回ModelAndView(mv),关于处理器适配器的作用,见第2部分的说明

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

   具体看getHandlerAdapter如何工作

 

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		Iterator it = this.handlerAdapters.iterator();
		while (it.hasNext()) {
			HandlerAdapter ha = (HandlerAdapter) it.next();
			if (logger.isDebugEnabled()) {
				logger.debug("Testing handler adapter [" + ha + "]");
			}
			if (ha.supports(handler)) {
				return ha;
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: Does your handler implement a supported interface like Controller?");
	}

    非常简单,仅仅是依次询问HandlerAdapter列表是否支持处理当前的处理器对象

4)倒序执行处理链拦截器列表的postHandle方法

 

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

5)根据ViewResolver获取相应的View实例,并生成视图响应给客户端

			// Did the handler return a view to render?
			if (mv != null && !mv.wasCleared()) {
				render(mv, processedRequest, response);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Null ModelAndView returned to DispatcherServlet with name '" +
							getServletName() + "': assuming HandlerAdapter completed request handling");
				}
			}

    再看看render方法

 

	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		// Determine locale for request and apply it to the response.
		Locale locale = this.localeResolver.resolveLocale(request);
		response.setLocale(locale);

		View view = null;

		if (mv.isReference()) {
			// We need to resolve the view name.
			view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'");
			}
		}
		else {
			// No need to lookup: the ModelAndView object contains the actual View object.
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'");
			}
		}

		// Delegate to the View object for rendering.
		if (logger.isDebugEnabled()) {
			logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		view.render(mv.getModelInternal(), request, response);
	}

6)倒序执行处理链拦截器列表的afterCompletion方法

	private void triggerAfterCompletion(
			HandlerExecutionChain mappedHandler, int interceptorIndex,
			HttpServletRequest request, HttpServletResponse response, Exception ex)
			throws Exception {

		// Apply afterCompletion methods of registered interceptors.
		if (mappedHandler != null) {
			HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
			if (interceptors != null) {
				for (int i = interceptorIndex; i >= 0; i--) {
					HandlerInterceptor interceptor = interceptors[i];
					try {
						interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex);
					}
					catch (Throwable ex2) {
						logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
					}
				}
			}
		}
	}
 

 

分享到:
评论
3 楼 jyjava 2011-12-11  
弱弱的问一句,这个是从哪里转的
2 楼 a123456603 2011-01-27  
哪几个比较重要的组件?俺正开始学。。。
1 楼 tantec 2009-05-22  
看来还需加油,当初我看源码,一头雾水。好在理解如何使用SpringMVC,了解了她的几个重要组件

相关推荐

Global site tag (gtag.js) - Google Analytics