[/code]
interface HandlerMapping 用来描述请求(request) 和 处理(handler)的映射(map)
主要方法:HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
根据请求返回一个HandlerExecutionChain 对象,该对象包含handler和对应的拦截器链,获取该对象后,在DispatcherServlet的doDispatch中先执行拦截器预处理,然后执行handler ,然后执行拦截器后处理,最后根据返回的ModelAndView 生成视图返回
一、DispatcherServlet实例化时执行静态块加载默认的初始化信息保存在defaultStrategies属性里
[code="java"]
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方法: