文档章节

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

qwweeezhengwei
 qwweeezhengwei
发布于 2017/08/01 14:48
字数 763
阅读 49
收藏 0

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

 

© 著作权归作者所有

qwweeezhengwei
粉丝 0
博文 13
码字总数 31124
作品 0
成都
私信 提问
Spring源码分析之WebMVC

作者: 一字马胡 转载标志 【2018-01-07】 更新日志 导入 Spring源码分析系列文章索引: Spring源码分析之Bean的解析 Spring源码分析之Bean的加载 Spring源码分析之AOP 本文是系列文章的第四...

疼丸李白
2018/01/07
0
0
“过时”的SpringMVC我们到底在用什么?深入分析DispatchServlet源码

之前已经分析过了Spring的IOC(《零基础带你看Spring源码——IOC控制反转》)与AOP(《从源码入手,一文带你读懂Spring AOP面向切面编程》)的源码,本次就来分析下SpringMVC。本文先简述下目前S...

公众号_Zack说码
2018/11/22
46
0
Spring MVC源码学习一之初始化

一、简单提下使用入门(依赖于注解方式) 1、通过在web.xml中添加配置,引入spring mvc框架,类似于Struts2引入需要在web.xml中配置过滤器StrutsPrepareAndExecuteFilter一样,但是Spring MVC是...

silence88
2016/12/20
53
1
Spring mvc 上下文初始化过程

在软件开发的中,如果某些特性的使用比较普遍,那么这些特性往往可以作为平台特性来实现,通过对这些平台特性进行有效的封装,使其向其他应用开放。正是如此,Spring由于其IOC、AOP、事务处理...

乱舞
2018/06/29
101
0
Spring之BeanDefinition创建过程源码解析

BeanFactory的具体实现为DefaultListableBeanFactory,下面是一个简单的小例子: applicationContext.xml: 从上面程序中可以看出类XmlBeanDefinitionReader的loadBeanDefinitions方法触发了B...

zhuwensheng
2018/06/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

mysql概览

学习知识,首先要有一个总体的认识。以下为mysql概览 1-架构图 2-Detail csdn |简书 | 头条 | SegmentFault 思否 | 掘金 | 开源中国 |

程序员深夜写bug
今天
9
0
golang微服务框架go-micro 入门笔记2.2 micro工具之微应用利器micro web

micro web micro 功能非常强大,本文将详细阐述micro web 命令行的功能 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架...

非正式解决方案
今天
6
0
前端——使用base64编码在页面嵌入图片

因为页面中插入一个图片都要写明图片的路径——相对路径或者绝对路径。而除了具体的网站图片的图片地址,如果是在自己电脑文件夹里的图片,当我们的HTML文件在别人电脑上打开的时候图片则由于...

被毒打的程序猿
今天
8
0
Flutter 系列之Dart语言概述

Dart语言与其他语言究竟有什么不同呢?在已有的编程语言经验的基础上,我们该如何快速上手呢?本篇文章从编程语言中最重要的组成部分,也就是基础语法与类型变量出发,一起来学习Dart吧 一、...

過愙
今天
5
0
rime设置为默认简体

转载 https://github.com/ModerRAS/ModerRAS.github.io/blob/master/_posts/2018-11-07-rime%E8%AE%BE%E7%BD%AE%E4%B8%BA%E9%BB%98%E8%AE%A4%E7%AE%80%E4%BD%93.md 写在开始 我的Arch Linux上......

zhenruyan
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部