一,九大组件
1.handlerMapping
用来查找handler的,也就是处理器,对应的就是标签@RequestMapping。也就是说handler,可以是类,也可以是方法.
2.handlerAdapter
我们最原始的servlet处理方式可以知道,当一个请求到达的时候,是封装成request发送到servlet的doService(HttpServletRequest,HttpServletResponse)形式的,所以,要从传统的servlet模式转到spring mvc,这里就需要一个适配器,将对应的url,映射到对应的handler上面
3.handlerExceptionResolver
从名字上看,这个是处理handler异常的组件,此组件的作用是根据异常设置ModelAndView,之后交给渲染方法进行渲染,渲染方法将ModelAndView渲染成页面,返回给客户端。
4.ViewResolver
视图解析器,功能是将string类型的视图名解析为View类型的视图,只有一个resolveViewName()方法。View用来渲染页面,也就是将程序返回的参数和数据填入模板中。
5.RequestToViewNameTranslator
作用是从请求中获取ViewName,因为ViewResolver根据ViewName查找View,如果Handler处理完之后,没有设置View,也没有ViewName,这个时候就需要这个组件中查找ViewName。
6.LocaleResolver
ViewResolver组件的resolveViewName()方法需要两个参数,一个是ViewName,一个就是Locale,Locale的获得就是该组件需要提供的,它从请求中解析出Locale,表示一个区域。中国locale就是zh-CN。
7.ThemeResolver
解析主题,主题就是样式,图片以及他们所形成的显示效果的集合,spring mvc主题对应一个properties文件,里面存放着当前主题相关的所有资源。
8.MultipartResolver
用于处理上传请求,通过将普通的请求包装成MultipartHttpServletRequest来实现,它可以通过getFIle()直接获取文件。简单来说就是封装请求,使其有文件上传的功能
9.FlashMapManager
从名字可以知道,FlashMap的管理者,FlashMap用于重定向时的参数传递,
二,源码
继续回到DIspatcher类中的InitStrategies()方法:
1.initMultiparResolver()
多文件上传的组件,
private void initMultipartResolver(ApplicationContext context) {
try {
//从容器中 获取bean 注意这些常量全是 bean的名字,他们在context初始化也就是Onfresh()方法的时候,已经把对应的Bean放入了容器中
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
.....
}
我们看一下这些常量字段:
很明显,这下面9个字段,正好对应9个组件,同时这9个字符串作为bean的名字,自然有对象的class对象,他们的具体实现保存在了一个Dispatcher.properties文件中。他们都会在spring mvc容器刷新的时候进行实例化,存放到容器中。
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
第一个组件初始化比较简单,就是从容器中获取到对象的bean,然后注入到Servlet中,等待后面处理请求的时候进行调用。
2.initLocalResolver()
初始化本地语言环境,它的操作和上面的多文件上传组件相同
private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
...
}
3.initThemeResolver()
同样是getBean()操作
private void initThemeResolver(ApplicationContext context) {
try {
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
...
}
4.initHandlerMapping()
处理器很重要,所以它的初始化也稍显不同,注意看下面的英文注解
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//默认为true,即默认从所有的ioc容器中获取handlerMapping
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else { //否者从当前的Ioc容器中通过 getBean()获取所有bean名称为"handlerMapping"的handlerMapping
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
....
}
//如果没有handlerMapping,则从配置文件中获取
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
}
英文注解的含义比较清楚,首先从applicationContext中找到所以的hanlderMapping实现类,然后保存到Map中,如果不为空,则把map转成ArrayList保存,抛掉HandlerMapping的名字,如果HandlerMapping为空,那么就需要从web.xml中获取配置的类,
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key); //从web.xml中获取
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length); //先创建一个空集合
for (String className : classNames) { //遍历反射创建
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
} ...
}
return strategies;
}
else {
return new LinkedList<>();
}
}
5.initHandlerAdapters()
初始化handler适配器,它的初始化模式和HandlerMapping完全一样,
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
...
}
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
...
}
}
后面的组件初始化内容也差不多,这里就不展开叙述了