您的位置:首页 > 编程语言 > Java开发

SpringMVC源码解析(下)

2009-05-22 12:11 337 查看

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;
}
阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: