核心架构的具体流程步骤如下:
1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
用我的话来概括如下:
由HandlerMapping得到HandlerExecutionChain(其包含Object handler,interceptors),handler就是Controller实例,接着由handler得到HandlerAdapter(ha),最后由ha.handle(..)得到ModelAndView。注意,在执行目标方法之前,会升序调用interceptors,之后又会倒序调用interceptors。那么,HandlerAdapter是个什么东西呢,我在DispatcherServlet.properties里可以看到默认配了3种adapter,其实还有一种adapter没加进配置文件,如果你了解springmvc的发展史和解决mvc的思路,你就会明白为什么有多种实现方式了。最初springmvc采用的是实现Controller接口的方式,javase 1.5开始,springmvc采用了更方便的注解方式来标明Controller类,这两种方式对应的adapter分别是SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter,所以我们可以重点关注AnnotationMethodHandlerAdapter。
下面来好好谈谈DispatcherServlet的部分代码
我们注意到该类中定义了一些well-known常量,呵呵,众所周知的常量
- public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
- public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
- public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
- /**
- * Well-known name for the HandlerMapping object in the bean factory for this namespace.
- * Only used when "detectAllHandlerMappings" is turned off.
- * @see #setDetectAllHandlerMappings
- */
- public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
- public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
- public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
- public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
- public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
- public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
- private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
我们在配置文件中给相关组件bean命名时,可以保持和只写常量值一致,毕竟别人的命名是相当标准的,不过,这从逻辑上不是必须的,你甚至可以不声明bean的id,因为该类提供了如下变量
- /** Detect all HandlerMappings or just expect "handlerMapping" bean? */
- private boolean detectAllHandlerMappings = true;
- /** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */
- private boolean detectAllHandlerAdapters = true;
- /** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */
- private boolean detectAllHandlerExceptionResolvers = true;
- /** Detect all ViewResolvers or just expect "viewResolver" bean? */
- private boolean detectAllViewResolvers = true;
- /** Perform cleanup of request attributes after include request? */
- private boolean cleanupAfterInclude = true;
- /** MultipartResolver used by this servlet */
- private MultipartResolver multipartResolver;
- /** LocaleResolver used by this servlet */
- private LocaleResolver localeResolver;
- /** ThemeResolver used by this servlet */
- private ThemeResolver themeResolver;
- /** List of HandlerMappings used by this servlet */
- private List<HandlerMapping> handlerMappings;
- /** List of HandlerAdapters used by this servlet */
- private List<HandlerAdapter> handlerAdapters;
- /** List of HandlerExceptionResolvers used by this servlet */
- private List<HandlerExceptionResolver> handlerExceptionResolvers;
- /** RequestToViewNameTranslator used by this servlet */
- private RequestToViewNameTranslator viewNameTranslator;
- /** FlashMapManager used by this servlet */
- private FlashMapManager flashMapManager;
- /** List of ViewResolvers used by this servlet */
- private List<ViewResolver> viewResolvers;
初始化方法中,执行了组件的初始化
- protected void initStrategies(ApplicationContext context) {
- initMultipartResolver(context);
- initLocaleResolver(context);
- initThemeResolver(context);
- initHandlerMappings(context);
- initHandlerAdapters(context);
- initHandlerExceptionResolvers(context);
- initRequestToViewNameTranslator(context);
- initViewResolvers(context);
- initFlashMapManager(context);
- }
我们拿出initHandlerMappings(context)来瞅瞅
- /**
- * Initialize the HandlerMappings used by this class.
- * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
- * we default to BeanNameUrlHandlerMapping.
- */
- private void initHandlerMappings(ApplicationContext context) {
- this.handlerMappings = null;
- if (this.detectAllHandlerMappings) {
- // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
- Map<String, HandlerMapping> matchingBeans =
- BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
- if (!matchingBeans.isEmpty()) {
- this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
- // We keep HandlerMappings in sorted order.
- OrderComparator.sort(this.handlerMappings);
- }
- }
- else {
- try {
- HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
- this.handlerMappings = Collections.singletonList(hm);
- }
- catch (NoSuchBeanDefinitionException ex) {
- // Ignore, we'll add a default HandlerMapping later.
- }
- }
- // Ensure we have at least one HandlerMapping, by registering
- // a default HandlerMapping if no other mappings are found.
- if (this.handlerMappings == null) {
- this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
- if (logger.isDebugEnabled()) {
- logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
- }
- }
- }
通过该方法我们可以知道,当detectAllHandlerMappings为true时,直接到mvc容器及其父容器中寻找所有类型为HandlerMapping的bean,而detectAllHandlerMappings默认恰为true,因此我们完全可以不声明bean的id。当detectAllHandlerMappings为false时(可通过在web.xml里配置servlet参数来改变默认值),则在mvc容器寻找名为"handlerMapping"的bean。如以上两种情况都没找到bean,将会实例化DispatcherServlet.properties中配置的bean。
doService方法里有这么一段
- // 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));
- }
- }
- }
这是用于对页面有include的情况做的请求数据快照处理。
下面进入重点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 {
- // multipart包装处理,我们常用CommonsMultipartResolver
- processedRequest = checkMultipart(request);
- multipartRequestParsed = processedRequest != request;
- // Determine handler for the current request.
- mappedHandler = getHandler(processedRequest, false);
- if (mappedHandler == null || mappedHandler.getHandler() == null) { // 404
- 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. // 代码省略
- // 调用目标方法前,顺序执行拦截器
- if (!mappedHandler.applyPreHandle(processedRequest, response)) {
- return;
- }
- try {
- // Actually invoke the handler.
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- }
- finally {
- 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
- mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
- return;
- }
- // Clean up any resources used by a multipart request.
- if (multipartRequestParsed) {
- cleanupMultipart(processedRequest);
- }
- }
- }
HandlerExecutionChain
- boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
- if (getInterceptors() != null) {
- for (int i = 0; i < getInterceptors().length; i++) {
- HandlerInterceptor interceptor = getInterceptors()[i];
- if (!interceptor.preHandle(request, response, this.handler)) {
- triggerAfterCompletion(request, response, null);
- return false;
- }
- this.interceptorIndex = i;
- }
- }
- return true;
- }
- /**
- * Apply postHandle methods of registered interceptors.
- */
- void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
- if (getInterceptors() == null) {
- return;
- }
- for (int i = getInterceptors().length - 1; i >= 0; i--) {
- HandlerInterceptor interceptor = getInterceptors()[i];
- interceptor.postHandle(request, response, this.handler, mv);
- }
- }
- /**
- * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
- * Will just invoke afterCompletion for all interceptors whose preHandle invocation
- * has successfully completed and returned true.
- */
- void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
- throws Exception {
- if (getInterceptors() == null) {
- return;
- }
- for (int i = this.interceptorIndex; i >= 0; i--) {
- HandlerInterceptor interceptor = getInterceptors()[i];
- try {
- interceptor.afterCompletion(request, response, this.handler, ex);
- }
- catch (Throwable ex2) {
- logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
- }
- }
- }
HandlerInterceptor
- public interface HandlerInterceptor {
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception;
- void postHandle(
- HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
- throws Exception;
- void afterCompletion(
- HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- throws Exception;
- }
自定义
- public class ExceptionHandler implements HandlerExceptionResolver {
- @Override
- public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
- request.setAttribute("exception",ex.getMessage());
- ModelAndView mav = new ModelAndView();
- mav.setViewName("/error");
- return mav;
- }
- }
原文链接:[http://wely.iteye.com/blog/2296899]