Spring-mvc源码分析之handlerMappings初始化

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

 

转载于:https://my.oschina.net/u/1243105/blog/1498758

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值