在分析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>(); } }