1.整体结构
SpringMvc中三个主要的类,分别为HttpServletBean,FrameworkServlet,DispatcherServlet。
HttpServletBean直接继承HttpServlet, FrameworkServlet继承了HttpServletBean,DispatcherServlet继承了FrameworkServlet。
过程是这样的,启动tomcat的时候。
1.首先会调用HttpServletBean的init方法。
2.调用initServletBean方法,initServletBean在FrameworkServlet中进行了重写。
3.initServletBean方法中调用本类的initWebApplicationContext方法进行初始化容器的工作。
4. 初始化中又调用了onRefrsh方法,onRefrsh方法在DispatcherServlet进行重写,对SpringMvc的九大组件进行了初始化。
接下来看相关方法的核心代码。
/**
* HttpServletBean,因为继承了HttpServlet,又在web.xml中配置了,所以tomcat在启动的时候会执行该类的init方法。
* 完全可以把这个类当做一个Servlet来理解,事实也是如此,因为继承了HttpServlet。
*/
@Override
public final void init() throws ServletException {
try {
//读取Servlet配置的参数并封装到pvs变量中(web.xml配置的参数),requiredProperties为必须参数,没有配置则报异常
PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
//BeanWrapper为spring中的工具类,将一个对象封装为BeanWrapper,可操作对象的属性
//在这里,这个this,或者bw对象为DispatcherServlet,可通过断点来看到
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
//将获取到的配置参数设置到DispatcherServlet
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}
//模板方法,在FrameworkServlet中进行了实现,子类初始化入口
initServletBean();
}接下来看一下FrameworkServlet中的initServletBean。
/**
* FrameworkServlet中的initServletBean方法
* 这里面主要的代码只有两句,日志代码已经去掉
*/
@Override
protected final void initServletBean() throws ServletException {
try {
//核心代码,初始化WebApplicationContext,WebApplicationContext为SpringMvc容器
this.webApplicationContext = initWebApplicationContext();
//模板方法,空实现
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
}FrameworkServlet中的initWebApplicationContext方法
在该方法中主要做了三件事,获取spring根容器,2.获取webApplicationContext并根据情况调用onRefresh方法,3.将 webApplicationContext设置到ServletContext中。
/**
* FrameworkServlet中的initWebApplicationContext
* 省略了日志代码和原有注释
* @return
*/
protected WebApplicationContext initWebApplicationContext() {
//获取spring根容器rootContext
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
//如果在构造中初始化了webApplicationContext则会执行该if里面的逻辑
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
//尝试从ServletContext中获取WebApplicationContext
wac = findWebApplicationContext();
}
if (wac == null) {
//如果没有获取到则创建一个WebApplicationContext
wac = createWebApplicationContext(rootContext);
}
//boolean类型变量,默认为false,如果为false则执行onRefresh方法
//如果执行了上面的createWebApplicationContext方法,则会将refreshEventReceived设置为true
//因为在createWebApplicationContext中调用了onRefresh方法,所以会将标识设置为true
if (!this.refreshEventReceived) {
onRefresh(wac);
}
if (this.publishContext) {
//将WebApplicationContext保存到ServletContext中
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
} DispatcherServlet中的onRefresh方法
/**
* DispatcherServlet中的onRefresh方法
* 方法比较简单,调用了initStrategies
* 在initStrategies中初始化了SpringMvc的九大组件
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* 简单说明一下九大组件,后续详细分析
*/
protected void initStrategies(ApplicationContext context) {
//文件上传解析器
initMultipartResolver(context);
//国际化资源解析器
initLocaleResolver(context);
//主题解析器(用于更换css,图片等)
initThemeResolver(context);
//解析能够处理请求的方法
initHandlerMappings(context);
//具体处理请求时使用的适配器(Adapter执行某个Handler)
initHandlerAdapters(context);
//异常解析器
initHandlerExceptionResolvers(context);
//获取默认视图名字的工具
initRequestToViewNameTranslator(context);
//视图解析器
initViewResolvers(context);
//Redirect中传递参数的工具
initFlashMapManager(context);
}到这就结束了,简单的介绍了一下SpringMvc的基本构成以及初始化的过程,当然具体过程并不是这么简单,这里只是说一下大致流程,可以根据上述步骤打断点跟一下SpringMvc的初始化过程,在几个重要方法打断点即可,后续会对九大组件进行一个简单的解析,希望对大家有所帮助。
















