目录
一、引入
二、load-on-startup标签的作用
初始化过程:
我们知道Servlet是服务器端的Java程序,用于处理用户端的请求,其生命周期有四个阶段:加载及实例化,初始化,处理请求,销毁。而在SpringMVC中,只有一个DispatcherServlet用于拦截处理用户的所有请求,由于加载及实例化,销毁都是由Servlet容器执行的,所以我着重讲一下在SpringMVC中Servlet的初始化,处理请求部分。本片先介绍初始化这部分。
首先我们先看SpringMVC中DispatcherServlet的配置,我们知道Servlet都在Web.xml文件中配置,配置如下:
cassini
index.jsp
DispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:application.xml
1
DispatcherServlet
*.do
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
CharacterEncodingFilter
/
1.Tomcat发布Web项目,由于web.xml文件配置org.springframework.web.servlet.DispatcherServlet时添加了
startup>1,所以依次执行DispatcherServlet类静态代码块、构造方法和init方法,如下代码:
静态代码块:
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);//DEFAULT_STRATEGIES_PATH,该常量值为DispatcherServlet.properties,此文件详见spring-webmvc-4.3.10.RELEASE.jar
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
构造方法:
public DispatcherServlet() {
super();
setDispatchOptionsRequest(true);
}
init()方法:该方法继承自HttpServletBean抽象类,FrameworkServlet,DispatcherServlet 类均未重写该方法
(DispatcherServlet extends FrameworkServlet extends HttpServletBean),执行到这里,DispatcherServlet进行两次上转型。
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// Let subclasses do whatever initialization they like.
initServletBean();//注意这里的initServletBean()方法
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
2.执行DispatcherServlet类initServletBean()方法,该方法继承自FrameworkServlet抽象类,该方法是HttpServletBean类中的
抽象方法,FrameworkServlet抽象类重写了该方法,而DispatcherServlet类没有。执行到这里,DispatcherServlet进行一次下转
型。
@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 {
this.webApplicationContext = initWebApplicationContext();//注意这里的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;
}
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
3.执行DispatcherServlet类initWebApplicationContext()方法,该方法继承自FrameworkServlet抽象类
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
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) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {// refreshEventReceived全局变量为false
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);//注意这里的onRefresh(wac)方法
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
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;
}
4.执行DispatcherServlet类onRefresh(ApplicationContext context)方法,该方法为FrameworkServlet抽象类中的抽象方法,
DispatcherServlet类重写了该方法。
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
5.执行DispatcherServlet类initStrategies(ApplicationContext context)方法
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
到这里,DispatcherServlet类初始化完成。