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

SpringMVC源码解析(下)

阅读更多

4.请求-处理链映射(HandlerMapping)
   HandlerMapping定义了请求与处理链之间的映射的策略,见如下接口。

   public interface HandlerMapping {
    String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";

    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

   主要的继承类和继承结构如下

   其中
*AbstractHandlerMapping:定义了HandlerMapping实现的最基础的部分内容,包括拦截器列表和默认处理对象
*AbstractUrlHandlerMapping:在AbstractHandlerMapping的基础上,定义了从URL到处理对象的映射关系管理,其主要处理过程如下
   getHandlerInternal:

	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler for [" + lookupPath + "]");
		}
		Object handler = lookupHandler(lookupPath, request);
		if (handler == null) {
			// We need to care for the default handler directly, since we need to
			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
			Object rawHandler = null;
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(rawHandler, lookupPath);
			}
		}
		return handler;
	}

 

   lookupHandler:

	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// Direct match?
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath);
		}
		// Pattern match?
		String bestPathMatch = null;
		for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {
			String registeredPath = (String) it.next();
			if (getPathMatcher().match(registeredPath, urlPath) &&
					(bestPathMatch == null || bestPathMatch.length() < registeredPath.length())) {
				bestPathMatch = registeredPath;
			}
		}
		if (bestPathMatch != null) {
			handler = this.handlerMap.get(bestPathMatch);
			validateHandler(handler, request);
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPathMatch, urlPath);
			return buildPathExposingHandler(handler, pathWithinMapping);
		}
		// No handler found...
		return null;
	}

 另外,其定义了Handler的注册方法registerHandler

*AbstractDetectingUrlHandlerMapping:AbstractDetectingUrlHandlerMapping通过继承ApplicationObjectSupport实现了ApplicationContextAware接口,在初始化完成之后自动通过ApplicationObjectSupport.setApplicationContext-->AbstractDetectingUrlHandlerMapping.initApplicationContext-->AbstractDetectingUrlHandlerMapping.detectHandlers调用detectHandlers函数,该函数将注册到ApplicationContext的所有Bean对象逐一检查,由其子类实现的determineUrlsForHandler判断每个Bean对象对应的URL,并将URL与Bean的关系通过AbstractUrlHandlerMapping.registerHandler注册

	protected void detectHandlers() throws BeansException {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
		}
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		// Take any bean name or alias that begins with a slash.
		for (int i = 0; i < beanNames.length; i++) {
			String beanName = beanNames[i];
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
				// URL paths found: Let's consider it a handler.
				registerHandler(urls, beanName);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Rejected bean name '" + beanNames[i] + "': no URL paths identified");
				}
			}
		}
	}

 

*BeanNameUrlHandlerMapping:非常简单,其实现determineUrlsForHandler函数,如果一个Bean以“/”开头,则认为是一个处理器类,并且以bean的名字作为映射的url,处理过程如下

	protected String[] determineUrlsForHandler(String beanName) {
		List urls = new ArrayList();
		if (beanName.startsWith("/")) {
			urls.add(beanName);
		}
		String[] aliases = getApplicationContext().getAliases(beanName);
		for (int j = 0; j < aliases.length; j++) {
			if (aliases[j].startsWith("/")) {
				urls.add(aliases[j]);
			}
		}
		return StringUtils.toStringArray(urls);
	}

 

*DefaultAnnotationHandlerMapping:实现determineUrlsForHandler函数,检查每个Bean对象的类或者方法有没有RequestMapping这个Annotation,如果有,则将相应配置的URL作为该Bean对应处理的URL,处理过程如下

protected String[] determineUrlsForHandler(String beanName) {
		ApplicationContext context = getApplicationContext();
		Class<?> handlerType = context.getType(beanName);
		RequestMapping mapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);

		if (mapping == null && context instanceof ConfigurableApplicationContext &&
				context.containsBeanDefinition(beanName)) {
			ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context;
			BeanDefinition bd = cac.getBeanFactory().getMergedBeanDefinition(beanName);
			if (bd instanceof AbstractBeanDefinition) {
				AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
				if (abd.hasBeanClass()) {
					Class<?> beanClass = abd.getBeanClass();
					mapping = AnnotationUtils.findAnnotation(beanClass, RequestMapping.class);
				}
			}
		}

		if (mapping != null) {
			// @RequestMapping found at type level
			this.cachedMappings.put(handlerType, mapping);
			Set<String> urls = new LinkedHashSet<String>();
			String[] paths = mapping.value();
			if (paths.length > 0) {
				// @RequestMapping specifies paths at type level
				for (String path : paths) {
					addUrlsForPath(urls, path);
				}
				return StringUtils.toStringArray(urls);
			}
			else {
				// actual paths specified by @RequestMapping at method level
				return determineUrlsForHandlerMethods(handlerType);
			}
		}
		else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) {
			// @RequestMapping to be introspected at method level
			return determineUrlsForHandlerMethods(handlerType);
		}
		else {
			return null;
		}
	}

 

5.处理器适配器(HandlerAdapter)
   HandlerAdapter定义了处理类如何处理请求的策略,见如下接口

   public interface HandlerAdapter {
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    long getLastModified(HttpServletRequest request, Object handler);
}

   通过实现特定的策略,可以灵活地将任意对象转换成请求处理对象,主要实现包括:

1)SimpleControllerHandlerAdapter/HttpRequestHandlerAdapter/SimpleServletHandlerAdapter/ThrowawayController
   非常简单,面向实现实现了特定接口的处理类的情形,仅仅做一个代理执行处理,看一下其中SimpleControllerHandlerAdapter的代码如下,其特定处理实现了Controller接口的处理类

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

    public boolean supports(Object handler) {
        return (handler instanceof Controller);
    }

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return ((Controller) handler).handleRequest(request, response);
    }

    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }

}

 

2)AnnotationMethodHandlerAdapter
   通过配置特定的Annotation,定义了该如何注入参数、调用哪个方法、对返回参数如何处理,主要过程如下(AnnotationMethodHandlerAdapter.invokeHandlerMethod)

try {
            ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
            Method handlerMethod = methodResolver.resolveHandlerMethod(request);
            ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            ExtendedModelMap implicitModel = new ExtendedModelMap();

            Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
            ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, result, implicitModel, webRequest);
            methodInvoker.updateSessionAttributes(
                    handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
            return mav;
        }
        catch (NoSuchRequestHandlingMethodException ex) {
            return handleNoSuchRequestHandlingMethod(ex, request, response);
        }

*ServletHandlerMethodResolver(AnnotationMethodHandlerAdapter内部类):该类通过请求URL、请求Method和处理类的RequestMapping定义,最终确定该使用处理类的哪个方法来处理请求
*ServletHandlerMethodInvoker(AnnotationMethodHandlerAdapter内部类):检查处理类相应处理方法的参数以及相关的Annotation配置,确定如何转换需要的参数传入调用方法,并最终调用返回ModelAndView
6.视图策略(ViewResolver)
  ViewResolver定义了如何确定处理视图的View对象的策略,见如下接口

public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}
分享到:
评论

相关推荐

    springMvc源码分析

    springMvc源码分析springMvc源码分析springMvc源码分析springMvc源码分析springMvc源码分析springMvc源码分析

    springmvc源码流程解析

    springmvc源码流程解析

    springmvc源码

    - `springmvc_hello` 可能是简单的 Hello World 示例,展示了 Spring MVC 的基本使用。 - `spring_user` 可能是一个用户管理模块,涉及到 Hibernate 的实体类、持久化操作以及 Spring MVC 的 Controller。 5. **...

    spring及springmvc源码

    Spring MVC 的源码解析则会涉及Web应用的请求处理流程。当请求到达时,DispatcherServlet 负责调度,根据请求映射找到合适的控制器(Controller)。Controller 通常是实现了 `Controller` 接口或使用了 `@Controller...

    springMVC源码详解

    《看透SpringMVC源代码分析与实践》这...总的来说,深入学习SpringMVC源码能够提升我们的技术水平,使我们在面对复杂业务场景时更有信心。《看透SpringMVC源代码分析与实践》这本书无疑是实现这一目标的重要参考资料。

    SpringMvc深入理解源码分析视频

    本视频课程“SpringMvc深入理解源码分析”旨在帮助开发者深入理解Spring MVC的工作原理和核心机制,从而更好地利用它来构建高效、可维护的Web应用。 在Spring MVC中,主要涉及以下几个核心概念: 1. **...

    springmvc源码测试代码

    在本压缩包 "springmvc源码测试代码" 中,我们可能找到了用于理解和学习 Spring MVC 源码的测试代码。这里我们将深入探讨 Spring MVC 的核心概念、工作流程以及如何通过测试代码来理解其实现。 首先,Spring MVC 的...

    springmvc深入解析.pdf

    Spring MVC深入解析 Spring MVC是一个基于模型-视图-控制器(MVC)模式的Web应用程序框架,是Spring Framework的一部分。它提供了一个灵活的方式来构建Web应用程序,使得开发者可以轻松地创建复杂的Web应用程序。 ...

    spring源码、springMVC源码、springboot源码资料,轻松应对金三银四Java面试 99% Spring面试题

    本文将深入探讨Spring、SpringMVC和SpringBoot的源码,帮助你理解和掌握这三大框架的关键知识点,从而在金三银四的Java面试中脱颖而出。 首先,让我们从Spring框架开始。Spring的核心是依赖注入(Dependency ...

    swagger整合springMVC源码

    5. **源码解析** 在`swagger-demo`中,可以看到`SwaggerConfig`配置类是Swagger与SpringMVC整合的关键。`Docket`类是配置的核心,通过`apiInfo`和`select`方法来定义API的元数据和暴露范围。`@EnableSwagger2`注解...

    springmvc源码及帮助文档

    在源码中,你可以看到这些核心组件的实现细节,比如DispatcherServlet如何解析请求、HandlerMapping如何查找映射、ViewResolver如何解析视图。阅读源码有助于理解Spring MVC的工作机制,提高问题排查能力,也能启发...

    SpringMvc主要流程源码解析(1).zip

    在 SpringMvc 主要流程源码解析(1).vep 文件中,可能详细分析了以上各个步骤的源码实现,包括 DispatcherServlet、HandlerMapping、Controller、HandlerAdapter、DataBinder、ViewResolver 和 View 的工作原理。...

    SpringMVC源码分析系列

    综上所述,SpringMVC源码分析系列深入探讨了框架的内部工作机制,尤其关注了请求映射、参数绑定、数据转换和响应处理等方面的实现细节,这些都是构成SpringMVC强大功能的核心部分。通过理解这些组件的交互与协作,...

    springmvc框架源码.zip

    本压缩包包含SpringMVC的源码,对于学习和理解SpringMVC的工作原理及其内部机制非常有价值。 1. **DispatcherServlet**:SpringMVC的核心组件,它作为前端控制器,负责接收HTTP请求,并根据请求信息(如URL、HTTP...

    SpringMvc源码

    Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动...支持本地化(Locale)解析、主题(Theme)解析及文件上传等;

    powernode_springmvc源码.zip

    本文将围绕"powernode_springmvc源码.zip"中的各个章节,深入剖析 Spring MVC 的核心概念和工作原理。 1. **第一章:Hello Spring MVC** 这部分通常会介绍如何创建一个基本的 Spring MVC 项目,包括配置文件的设置...

    SpringMVC源码解析之消息转换器HttpMessageConverter

    SpringMVC源码解析之消息转换器HttpMessageConverter SpringMVC中的消息转换器HttpMessageConverter是实现请求报文和对象、对象和响应报文之间的自动转换的关键机制。该机制通过使用@RequestBody和@ResponseBody两...

    springboot + springMVC整合源码

    通过这个源码,你可以进一步学习SpringBoot的自动配置机制、SpringMVC的控制器设计模式、以及如何利用JdbcTemplate进行数据库操作。这些都是Java Web开发中的重要技能,对于理解和构建复杂的Web应用程序非常有帮助。

    spring源码合集spring源码合集

    7. **Bean生命周期源码解析**:"05-Spring之Bean生命周期源码解析下-周瑜"将详细阐述Bean从创建到销毁的整个过程,包括初始化、后置处理、正常运行和销毁等阶段,使我们能更好地控制和管理Bean的状态。 8. **模拟...

    SpringMVC简单源码实现

    在这个"SpringMVC简单源码实现"中,我们将会深入探讨SpringMVC的核心机制,包括请求处理、模型视图解析以及依赖注入等方面。 1. **请求处理流程**: 当一个HTTP请求到达SpringMVC应用时,它首先由前端控制器`...

Global site tag (gtag.js) - Google Analytics