SpringMVC DispatcherServlet的handlerMappings初始化

 

interface HandlerMapping 用来描述请求(request) 和 处理(handler)的映射(map)
主要方法:HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
根据请求返回一个HandlerExecutionChain 对象,该对象包含handler和对应的拦截器链,获取该对象后,在DispatcherServlet的doDispatch中先执行拦截器预处理,然后执行handler ,然后执行拦截器后处理,最后根据返回的ModelAndView 生成视图返回



一、DispatcherServlet实例化时执行静态块加载默认的初始化信息保存在defaultStrategies属性里
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized		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
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

.......
在DispatcherServlet的IOC容器中没有配置HandlerMapping bean时使用这个配置文件中配置的HandlerMapping。



====================================================================
二、在DispatcherServlet实例创建后,web容器会调用父类HttpServletBean的ini()方法,在该方法中调用initServletBean(),
由子类FrameworkServlet实现,完成DispatcherServlet的IOC容器创建和初始化
protected final void initServletBean() throws ServletException {
     ...
 //创建IOC容器,并初始化
    this.webApplicationContext = initWebApplicationContext();
     ...
}


protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext wac = findWebApplicationContext();
		if (wac == null) {
			// No fixed context defined for this servlet - create a local one.
			WebApplicationContext parent =
					WebApplicationContextUtils.getWebApplicationContext(getServletContext());
      //创建实例
	wac = createWebApplicationContext(parent);
		}

		if (!this.refreshEventReceived) {
          //由子类	DispatcherServlet实现						 onRefresh(wac);
		}

		.....

		return wac;
	}



在DispatcherServlet中重写了onRefresh
protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
	}



最终调用到initHandlerMappings(context)进行handlerMappings的初始化
private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
//是否需要一起找出parent中配置的HandlerMapping的bean
     if (this.detectAllHandlerMappings) {
//获取该容器以及所有parent容器中不重复的HandlerMapping类及其子类bean
  Map<String, HandlerMapping> matchingBeans =		BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
	if (!matchingBeans.isEmpty()) {
//如果配置了HandlerMapping类的bean,赋值给handlerMappings 
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
//排序实现了HandlerMapping接口,都要实现Ordered接口用来排序								OrderComparator.sort(this.handlerMappings);
			}
}
		else {
			try {
//从该容器中根据bean的名字,找出名为handlerMapping的bean
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.
			}
		}
		if (this.handlerMappings == null) {
//如果在容器中没获取到,根据读取配置文件defaultStrategies的信息,创建默认的HandlerMapping的list
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}






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





======================================================================
SimpleUrlHandlerMapping 实现:
首先在配置文件中定义
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <property name="mappings">
               <props>
                   <prop key="login.do">LoginAction</prop>
               </props>
            </property>
</bean>

SimpleUrlHandlerMapping 类中有这2个方法:
  public void setMappings(Properties mappings) {
CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
	} 

public void setUrlMap(Map<String, ?> urlMap) {
		this.urlMap.putAll(urlMap);
	}


根据命名规则可以使用<property name="mappings">或<map name="urlMap">来配置映射。

SimpleUrlHandlerMapping 最上父类ApplicationObjectSupport 实现了ApplicationContextAware,当handlerMappings实例创建也就是调用getBean方法时,在AbstractAutowireCapableBeanFactory中
 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
       //创建bean实例
		if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
   .......
		Object exposedObject = bean;
		try {
  //根据容器中注册的bean定义设值属性
	populateBean(beanName, mbd, instanceWrapper);
			if (exposedObject != null) {
  //初始化方法调用
	exposedObject = initializeBean(beanName, exposedObject, mbd);
			}
   .......
		}
     


在initializeBean方法中调用了ApplicationContextAwareProcessor的postProcessBeforeInitialization方法,在这个方法中调用了该类的invokeAwareInterfaces(bean);
private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationContextAware) {
//容器调用实现了ApplicationContextAware接口的方法
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}


在SimpleUrlHandlerMapping中重写了该方法
@Override
public void initApplicationContext() throws BeansException {
		super.initApplicationContext();
		registerHandlers(this.urlMap);
	}

protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
		if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
		}
		else {
			for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
	String url = entry.getKey();
	Object handler = entry.getValue();
								if (!url.startsWith("/")) {
			url = "/" + url;
				}
								if (handler instanceof String) {
		handler = ((String) handler).trim();
			}
//调用父类AbstractUrlHandlerMapping方法注册到该类的handlerMap中,在getHandler实现中使用这个map
	registerHandler(url, handler);
			}
		}
	}


AbstractUrlHandlerMapping中registerHandler方法:



你可能感兴趣的:(bean,Web,mvc,servlet,IOC)