在分析spring源码的时候,咱们知道handlerMapping是springMvc的一个组件,他的做用就是经过HandlerMapping找到具体Controller的具体类。那么初始化的时候在DispatcherServlet中handlerMappings是怎么初始化的呢?java
一、咱们知道在SpringMvc容器初始化的时候他会执行onRefresh方法web
//--DispatcherServlet类中的onRefresh方法 @Override protected void onRefresh(ApplicationContext context) { //这里会完成一些组件的初始化 initStrategies(context); }
/** * Initialize the strategy objects that this servlet uses. * <p>May be overridden in subclasses in order to initialize further strategy objects. */ protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); //这里咱们主要关注一下HandlerMappings的初始化 initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
那咱们看看initHandlerMappings(context)究竟是怎么初始化的呢?spring
【DispatcherServlet.java】 /** Detect all HandlerMappings or just expect "handlerMapping" bean? */ private boolean detectAllHandlerMappings = true; /** * 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; //在DispatcherServlet中咱们看到detectAllHandlerMappings属性默认值是true if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. //首先这里会在SpringContext容器中去查找类型为HandlerMapping的类。 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. AnnotationAwareOrderComparator.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) { //获取默认的HandlerMapping#关键代码在这里 this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } } }
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class)执行完毕后,返回了默认的HandlerMapping的初始化mvc
【DispatcherServlet.java】 //这里是一个常量,咱们看到他定义了properties文件的加载路径 private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties"; private static final Properties defaultStrategies; //这里咱们看到在DispatcherServlet初始化的时候,执行了一句静态语句块代码,这里主要是完成defaultStrategies资源初始化的问题。而且属性上面加了final和static也就是只能被初始化一次且不能更改 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()); } } --这里有必要看一看DispatcherServlet.properties配置文件关于HandlerMapping的配置 org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping 经过配置文件咱们看到,关于HandlerMapping这里定义了二个默认的实现类 //Return:BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping的实例 @SuppressWarnings("unchecked") protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { //strategyInterface就是HandlerMapping.class //key的值为org.springframework.web.servlet.HandlerMapping String key = strategyInterface.getName(); //这里经过key在properties中去查找默认的配置信息 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()); //这里就是一个类初始化的问题。经过ApplicationContext建立一个bean。也就是让这个bean经过spring容器进行管理 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>(); } }