- 从HttpServletBean中知,FrameworkServlet的初始化入口方法是initServletBean(),其代码如下:
/**
* Overridden method of {@link HttpServletBean}, invoked after any bean properties
* have been set. Creates this servlet's WebApplicationContext.
*/
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
//初始化webApplicationContext
this.webApplicationContext = initWebApplicationContext();
//初始化FrameworkServlet,子类可以覆盖然后在里面做一些初始化工作,但子类并没有使用它
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
1.1 可见FrameworkServlet在构建过程中的主要作用就是初始化webApplicationContext
protected WebApplicationContext initWebApplicationContext() {
//获取rootContext
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
//如果已经通过构造方法设置了webApplicationContext(第一种获取WebApplicationContext的方法)
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
/**
* 通过配置在ServletContext中的参数contextAttribute中获取WebApplicationContext
* (同时在本servlet被初始化或调用之前,WebApplicationContext必须已经在ServletContext中被加载或者存储)
* (第二种获取WebApplicationContext的方法)
*/
wac = findWebApplicationContext();
}
if (wac == null) {
//还没有webApplicationContext,创建一个.正常情况下用这个
//(第三种获取WebApplicationContext的方法)
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
//当ContextRefreshedEvent事件没有被触发时调用
onRefresh(wac);
}
if (this.publishContext) {
//将WebApplicationContext保存到ServletContext中
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
总结: initWebApplicationContext方法做了三件事
a) 获取spring的根容器rootContext
b) 设置WebApplicationContext并根据情况调用onRefresh方法,不管用哪种方式调用onRefresh最终肯定会被调用一次,而且只调用一次
c) 将webApplicationContext设置到ServletContext中