A new bookJava concurrent programming system and modelOnline, welcome to read.
When using Spring MVC, the standard configuration looks like this:
1. The ContextLoaderListener configuration:
<! <context-param> <! -- Name --> <param-name>contextConfigLocation</param-name> <! Classpath :application-context. XML </param-value> </context-param> <context-param> <param-name>webAppRootKey</param-name> <param-value>meipian</param-value> </context-param> <! -- Spring listener configuration --> <listener> <! - in the Spring - web package under the context - > < listener - class > org. Springframework. Web. Context. ContextLoaderListener < / listener - class > </listener>Copy the code
2.DispatcherServlet configuration:
<servlet> <servlet-name>meipian</servlet-name> <! - a core controller configuration for SpringMVC - > < the servlet class - > org. Springframework. Web. Servlet. DispatcherServlet < / servlet class - > < init - param > <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>meipian</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>Copy the code
The ContextLoaderListener automatically assembs the configuration information of the ApplicationContext when the Web container is started. Because it implements the ServletContextListener interface, the methods it implements are executed by default when the web.xml is configured to start the container. The container used by Spring MVC is WebApplicationContext. What does it have to do with the ApplicationContext that ContextLoaderListener initializes?
We can start with the initialization of the DispatcherServlet: The DispatcherServlet intercepts all requests, so accessing any interface initializes the DispatcherServlet object.
Initializing the DispatcherServlet does a very simple thing:
public DispatcherServlet() {
super(a); setDispatchOptionsRequest(true);
}Copy the code
Its parent class FrameworkServlet initializes nothing:Copy the code
public FrameworkServlet() {
}Copy the code
Tomcat then calls the init method of the DispatcherServlet and only executes the init() method once during the lifetime of the Servlet. It is executed when the server loads the Servlet. The server can be configured to load servlets when the server is started or when a client accesses them for the first time. No matter how many clients access the Servlet, init() is never repeated. Don’t ask me why I called init, it’s the servlet specification. The init method of DispatcherServlet is implemented in the parent class HttpServlet of the FrameworkServlet:
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
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) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}
// Let subclasses do whatever initialization they like.
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully"); }}Copy the code
The initServletBean() method that calls the DispatcherServlet is the method that initializes the WebApplicationContext. This method is implemented in its subclass FrameServlet method:
@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(); // Initialize the WebApplicationContext object
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"); }}Copy the code
InitWebApplicationContext method as follows:
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 parentcwac.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) {
// 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);
}
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;
}Copy the code
Will default to createWebApplicationContext method:Copy the code
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { Class<? > contextClass = getContextClass();if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet with name '" + getServletName() +
"' will try to create custom WebApplicationContext context of class '" +
contextClass.getName() + "'" + ", using parent context [" + parent + "]");
}
if(! ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
configureAndRefreshWebApplicationContext(wac);
return wac;
}Copy the code
In the absence of contexloaderListener,parent is empty. With contexloaderListener, parent is not empty.
And in the Spring MVC configuration, if you write the Service configuration together with the MVC configuration, it doesn’t matter if there is a contexloaderListener.
This illustrates what the contexloaderListener does.