在看完spring
源码后,有个疑问handlerMappings
以及的handlerAdapters
是何时被初始化的?
1.看到DispatcherServlet
的initHandlerMappings
方法:这个方法初始化了handlerMappings
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException var3) {。。。 }
if (this.handlerMappings == null) {
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
。。。
在该类中发现,是在initStrategies
方法中执行初始化的,同时发现好多组件都是在这个方法中执行,比如另一个重要的对象handler
适配器。而initStrategies
又是在onRefresh
中执行
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
//初始化所有HandlerMapping
this.initHandlerMappings(context);
//初始化所有HandlerAdapter
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
归根究底,其springMVC
的初始化是在onRefresh()
这个方法中执行的。
2.下面首先通过时序图来探索springMVC
的初始化流程:(图片来源于网络)
2.1 servlet
初始化会调用 init
方法,换句话说就是springMVC
进行初始化的时候首先会去执行HttpServletBean
的init
方法, 下面看看HttpServletBean
的init
方法源码:
public final void init() throws ServletException {
。。。
//从init参数设置bean属性
PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
this.initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
} catch (BeansException var4) {
。。。。。
}
//让子类FrameworkServlet实现
this.initServletBean();
。。。。
果然出现了流程图中的initServletBean
。
2.2 接下来 FramworkServlet
会执行 initServletBean
这个方法,下面就继续看看 initServletBean
方法源码:
protected final void initServletBean() throws ServletException {
this.getServletContext().log("Initializing Spring FrameworkServlet '" + this.getServletName() + "'");
。。。
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = this.initWebApplicationContext();
this.initFrameworkServlet();
}
。。。
可以看到 initServletBean
方法中就调用了一个 initFrameworkServlet
方法和 initWebApplicationContext
方法,其中initFrameworkServlet
方法是由子类实现,这个不多说,直接看 initWebApplicationContext
方法源码。
2.3 initWebApplicationContext
方法源码:
protected WebApplicationContext initWebApplicationContext() {
//此处的 rootContext便是springioc容器, 在你配置web.xml的ContextLoaderListener的时候注入的
//通过分析ContextLoaderListenr的源码,可以看到
//ContextLoaderListener通过ContextLoader根据ApplicationContext.xml的配置会创建一个xmlWebApplicationContext
//如果没有配置ContextLoaderListener,本处将为null,但不影响springMVC,为何?通过接下来的分析,就能看到原因
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
WebApplicationContext wac = null;
//当webApplicationContext已经存在,即springmvc容器已经存在,那么就直接使用,使用之前会先设置rootContext,为其根
//配置完成之后refresh一次,refresh会涉及到IOC的内容,本处不做探讨。
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
//设置springIOC容器为spring mvc容器的父同期
cwac.setParent(rootContext);
}
this.configureAndRefreshWebApplicationContext(cwac);
}
}
}
//如果不存在webApplicationContext,那么先去ServletContext中查找
if (wac == null) {
wac = this.findWebApplicationContext();
}
//如果上述没有查到,那么就创建webApplicationContext
if (wac == null) {
//创建springmvc容器
wac = this.createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
//此方法由DispatcherServlet调用,初始化创建好的springmvc容器
this.onRefresh(wac);
}
//将webApplicationContext保存在ServletContext
if (this.publishContext) {
//将上下文发布为servlet上下文属性。
String attrName = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName, wac);
。。。
}
return wac;
}
FrameworkServlet
初始化web
应用上下文的时候会调用onRefresh
()方法,这个方法是留给其子类DispatcherServlet
调用的, 最后就该看看DispatcherServlet
里面的 onRefresh
方法了:
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
//初始化此servlet使用的策略对象。
//可以在子类中重写以初始化其他策略对象
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
可以看到onRefresh
方法就一句话,调用initStrategies
方法, 上面给出了 initStrategies
源码, 很直观,就是在初始化springMVC
的一系列组件, 但是此处你要明白,SpringMVC
的组件其实已经在webApplicationContext
创建时就已经实例化了, 此处所谓的初始化只是在选择合适的组件(每一个组件都对应了几个不同的实现)。
到此,就可以很清楚知道,HandlerMappings
和HandlerAdapter
等是在什么时候初始化的。