在分析HandlerMapping和HandlerAdapter以及其子类关系和代码之前,我们先来看看DispatcherServlet对它们的初始化是怎样的,在DispatcherServlet类中,有HandlerMapping和HandlerAdapter的链表。
/** List of HandlerMappings used by this servlet */ private List<HandlerMapping> handlerMappings; /** List of HandlerAdapters used by this servlet */ private List<HandlerAdapter> handlerAdapters;
下面的布尔属性是DispatcherServlet中用来标记探测结果的,true表示探测所有的HandlerMapping,false表示只探测已在***-servlet.xml中声明的handlerMapping bean,Adapter同上。
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */ private boolean detectAllHandlerMappings = true; /** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */ private boolean detectAllHandlerAdapters = true;
下面是HandlerMapping的初始化方法:
/** * 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"); } } }
前面的一个if...else...很好理解,就是根据是否探测上下文中所有bean name不管是handlerMapping还是不是的HandlerMapping实体bean。第二个if,当在上下文中没有找到注册的HandlerMapping时进入该条件,注意方法getDefaultStrategies,它有两个参数,一个是上下文,一个是Class对象。
/** * Create a List of default strategy objects for the given strategy interface. * <p>The default implementation uses the "DispatcherServlet.properties" file (in the same * package as the DispatcherServlet class) to determine the class names. It instantiates * the strategy objects through the context's BeanFactory. * @param context the current WebApplicationContext * @param strategyInterface the strategy interface * @return the List of corresponding strategy objects */ @SuppressWarnings("unchecked") protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { String key = strategyInterface.getName(); String value = defaultStrategies.getProperty(key); if (value != null) { String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List<T> strategies = new ArrayList<T>(classNames.length); for (String className : classNames) { try { Class clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); Object strategy = createDefaultStrategy(context, clazz); strategies.add((T) strategy); } catch (ClassNotFoundException ex) { throw new BeanInitializationException( "Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", ex); } catch (LinkageError err) { throw new BeanInitializationException( "Error loading DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]: problem with class file or dependent class", err); } } return strategies; } else { return new LinkedList<T>(); } }
String key这一行就不用解释了,就是得到类名,请看第二行
String value = defaultStrategies.getProperty(key);
这里defaultStrategies是DispatcherSerlvet的属性
private static final Properties defaultStrategies; 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()); } }
/** * Name of the class path resource (relative to the DispatcherServlet class) that defines DispatcherServlet's default * strategy names. */ private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
在DispatcherServlet的静态域,即第一次实例化该类时,运行的区域,读取了DispatcherSerlvet.properties这个配置文件,Properties类就不解释了,打开源码目录的时候,我们可以看到在DispatcherSerlvet.java的同级目录下有这个配置文件K=V。
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.annotation.AnnotationMethodHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
可以看到HandlerMapping的默认类有BeanNameUrlHandlerMapping(bean和Url直直接映射的解析HandlerMapping),DefaultAnnotationHandlerMapping(默认注解支持的HandlerMapping)。
我们继续向下看getDefaultStrategies部分的源码,当得到value的String值之后,将String进行破分,变为String数组,并对BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping进行bean的创建,使用语句
Object strategy = createDefaultStrategy(context, clazz);
该方法内部:
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) { return context.getAutowireCapableBeanFactory().createBean(clazz); }
将创建后的bean加入到链表strategies中并返回。
这样HandlerMapping的链表就初始化完成了。
HandlerAdapter也是同理。
这一篇已经太长了,所以将重点介绍放在下一节。