在分析spring源码的时候,我们知道handlerMapping是springMvc的一个组件,他的作用就是通过HandlerMapping找到具体Controller的具体类。那么初始化的时候在DispatcherServlet中handlerMappings是怎么初始化的呢?
1、我们知道在SpringMvc容器初始化的时候他会执行onRefresh方法
//--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)到底是怎么初始化的呢?
【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的初始化
【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>();
}
}