详述load-on-startup标签的作用

目录

 

一、引入

二、load-on-startup标签的作用

初始化过程:


一、引入

我们知道Servlet是服务器端的Java程序,用于处理用户端的请求,其生命周期有四个阶段:加载及实例化初始化处理请求销毁。而在SpringMVC中,只有一个DispatcherServlet用于拦截处理用户的所有请求,由于加载及实例化销毁都是由Servlet容器执行的,所以我着重讲一下在SpringMVC中Servlet的初始化处理请求部分。本片先介绍初始化这部分。

二、load-on-startup标签的作用

首先我们先看SpringMVC中DispatcherServlet的配置,我们知道Servlet都在Web.xml文件中配置,配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>cassini</display-name>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
	
	<servlet>
		<servlet-name>DispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:application.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup><!--用于配置Servlet的初始化-->
	</servlet>
	
	<servlet-mapping>
		<servlet-name>DispatcherServlet</servlet-name>
		<url-pattern>*.do</url-pattern><!--该标签用于配置处理请求时的请求处理者-->
	</servlet-mapping>
	
	<filter><!--配置字符过滤器-->
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/</url-pattern>
	</filter-mapping>
</web-app>

初始化过程:

1.Tomcat发布Web项目,由于web.xml文件配置org.springframework.web.servlet.DispatcherServlet时添加了<load-on-

startup>1</load-on-startup>,所以依次执行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());
	}
}

构造方法:

扫描二维码关注公众号,回复: 10856358 查看本文章
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.执行DispatcherServletinitServletBean()方法,该方法继承自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.执行DispatcherServletinitWebApplicationContext()方法,该方法继承自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.执行DispatcherServletonRefresh(ApplicationContext context)方法,该方法为FrameworkServlet抽象类中的抽象方法,

DispatcherServlet类重写了该方法。

@Override
protected void onRefresh(ApplicationContext context) {
	initStrategies(context);
}

5.执行DispatcherServletinitStrategies(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类初始化完成。

发布了91 篇原创文章 · 获赞 10 · 访问量 8013

猜你喜欢

转载自blog.csdn.net/Liuxiaoyang1999/article/details/105121586
今日推荐