From the web XML on the initialization process of spring MVC integration with spring

Posted by feldon23 on Thu, 24 Feb 2022 12:19:10 +0100

1, About servlet s

  1. Explain servlet in detail, https://www.runoob.com/servlet/servlet-tutorial.html
  2. Overview:
  • Servlet and servlet container

Java Servlet (Java Server applet) is a Web component based on Java technology. It runs on the server side. It is managed by the servlet container and used to generate dynamic content. Servlet is a platform independent Java class. Writing a servlet is actually writing a Java class according to the servlet specification. Servlet is compiled into platform independent bytecode, which can be dynamically loaded into the Web server supporting Java technology.

  • Servlet container, also known as servlet engine, is a part of Web server or application server. It is used to provide network services on the sent requests and responses, decode MIME based requests and format MIME based responses. A servlet does not have a main method and cannot run independently. It must be deployed into a servlet container, which instantiates and calls the servlet's methods (such as doGet() and doPost()), and the servlet container contains and manages servlets within the servlet's life cycle. After the introduction of JSP technology, the container that manages and runs Servlet/JSP is also called Web container.

(Note: common MIME types: text/html, application/pdf, video/quicktime, application /java, image/jpeg, application/jar, application / octet stream, application/x- zip)

After having a servlet, users can access the servlet by clicking a link or directly entering a URL in the address bar of the browser. After receiving the request, the Web server does not directly hand over the request to the servlet, but to the servlet container. The servlet container instantiates the servlet, calls a specific method of the servlet, processes the request, and generates a response. The response is returned to the Web server by the servlet container. The Web server wraps the response and sends it to the Web browser in the form of HTTP response.

  • What does the servlet container provide?

We know that servlets need to be managed and run by the servlet container, but why? The reasons for using servlet containers are:

  • Communication support: using the method provided by the container, you can easily make the servlet talk to the web server without setting up a server socket, listening to a port, creating a stream, etc. The container knows the protocol between itself and the web server, so your servlet doesn't have to worry about the API between the web server (such as Apache, jetty) and your own web code. It only needs to consider how to implement business logic in the servlet (such as processing an order).

  • Life cycle management: servlet container controls the life and death of servlets. It is responsible for loading classes, instantiating and initializing servlets, calling servlet methods, and garbage collection of servlet instances. With servlet container, you don't need to think too much about resource management.

  • Multithreading support: the container automatically creates a new java thread for each servlet request it receives. For the user's request, if the servlet has run the corresponding http service method, this thread will end. This is not to say that you don't need to consider thread safety. In fact, you will encounter synchronization problems, but it will save you a lot of work.

  • Declarative way to achieve security: using servlet container, you can use xml deployment description file to configure and modify security without having to hard code it into servlet class code.

  • JSP support: the servlet container is responsible for translating JSP code into real java code.

  • Servlet s have the following advantages:
  • Servlet is a single instance multithreaded operation mode. Each request runs in an independent thread, while there is only one servlet instance providing services.
  • Servlets are scalable and can respond to more requests, because the Servlet container uses a thread instead of an operating system process, and threads only occupy limited system resources.
  • Servlet s use standard API s and are supported by more Web servers.
  • Servlet is written in Java language, so it has all the advantages of Java programming language, including easy development and platform independence.
  • Servlet can access the rich class libraries of Java platform, which makes the development of various applications easier.
  • The Servlet container provides additional functions to servlets, such as error handling and security.

In fact, servlet is a technology that uses http protocol to communicate between server and client. Socket is an application of socket.

  • Tomcat

Learning Servlet Technology requires a servlet running environment, that is, a servlet container. Tomcat is used in this paper. There are others like jetty. Like IIS, Apache and other Web servers, Tomcat has the function of processing HTML pages. In addition, it is also a servlet and JSP container. The independent servlet container is the default mode of Tomcat. However, Tomcat's ability to handle static html is not as good as Apache. We can integrate Apache and Tomcat together. Apache is used as HTTP Web server and Tomcat is used as Web container. About the difference between Apache and Tomcat.

The process of Tomcat server accepting and responding to customer requests is as follows:

  1. The client (usually a browser) accesses the Web server and sends HTTP requests.
  2. After receiving the request, the Web server passes it to the Servlet container.
  3. The Servlet container loads the Servlet, generates the Servlet instance, and passes the object representing the request and response to it.
  4. The Servlet instance uses the request object to get the request information of the client, and then processes it accordingly.
  5. The Servlet instance sends the processing results back to the client through the response object. The container is responsible for ensuring that the response is sent correctly and returning the control to the Web server.

2, From the web XML speaking

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">


    <!-- spring Configuration files, including opening bean Scanning, aop,affair -->
    <!-- Spring Loaded xml file,Not configured, default to applicationContext.xml -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-config.xml</param-value>
    </context-param>
    
    <!--ContextLoaderListener Used at startup web When the container is, go to the above location to read the configuration file and initialize it Spring Container. Start the parent container, i.e IOC Container, management Dao,Service-->
    <!-- This class acts as spring of listener When used, it will be found automatically when it is created web.xml Configured applicationContext.xml file -->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <!--spring mvc to configure-->
    <!-- to configure Spring MVC of DispatcherServlet,It can also be configured to inherit DispatcherServlet Custom classes for,Configuration here spring mvc Configuration of(scanning controller) -->
    <!--Used to start the sub container, i.e springMVC container-->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  • Loading of spring parent container

When Tomcat starts, it will load the web in turn Listener, Filter and Servlet configured in XML. Therefore, according to the above configuration, the ContextLoaderListener will be loaded first. This class inherits the ContextLoader and is used to initialize the Spring root context and put it into the ServletContext.

Implement javax Servlet. The servletcontextlistener interface inherits the ContextLoader class to initialize and destroy the WebApplicationContext container respectively when the Servlet container is started and closed

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
	public ContextLoaderListener() {
	}
    /**
     * As of Spring 3.1, supports injecting the root web application context
     */
	public ContextLoaderListener(WebApplicationContext context) {
		super(context);
	}
	/**
	 * Initialize the root web application context.
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
        // <1> Initialize Root WebApplicationContext
		initWebApplicationContext(event.getServletContext());
	}
	/**
	 * Close the root web application context.
	 */
	@Override
	public void contextDestroyed(ServletContextEvent event) {
        // <2> Destroy Root WebApplicationContext
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}
}

Let's take this as the entry to analyze the code. The Tomcat container will first call the contextInitialized () method of ContextLoadListener, which in turn calls the initWebApplicationContext() method of the parent ContextLoader. The following is the source code of this method.

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
//If the Spring container already exists in the ServletContext, an error will be reported
if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
		throw new IllegalStateException(
				"Cannot initialize context because there is already a root application context present - " +
				"check whether you have multiple ContextLoader* definitions in your web.xml!");
	}
	Log logger = LogFactory.getLog(ContextLoader.class);
	servletContext.log("Initializing Spring root WebApplicationContext");
	if (logger.isInfoEnabled()) {
		logger.info("Root WebApplicationContext: initialization started");
	}
	long startTime = System.currentTimeMillis();
	try {
		// Store context in local instance variable, to guarantee that
		// it is available on ServletContext shutdown.
		if (this.context == null) {
            //webApplicationContext is created here, and XmlWebApplicationContext is created by default
            //If you want to customize the implementation class, you can Configure the parameter contextClass in < context param > of XML
            //At this time, the Context has not been configured, which is equivalent to an "empty shell"
			this.context = createWebApplicationContext(servletContext);
		}
		if (this.context instanceof ConfigurableWebApplicationContext) {
			ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
			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 ->
					// determine parent for root web application context, if any.
					ApplicationContext parent = loadParentContext(servletContext);
					cwac.setParent(parent);
				}
                //Read the configuration file of Spring and initialize the parent context
				configureAndRefreshWebApplicationContext(cwac, servletContext);
			}
		}
        //Store the root context into ServletContext.
    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

		ClassLoader ccl = Thread.currentThread().getContextClassLoader();
		if (ccl == ContextLoader.class.getClassLoader()) {
			currentContext = this.context;
		}
		else if (ccl != null) {
			currentContextPerThread.put(ccl, this.context);
		}
		if (logger.isDebugEnabled()) {
			logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
					WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
		}
		if (logger.isInfoEnabled()) {
			long elapsedTime = System.currentTimeMillis() - startTime;
			logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
		}
		return this.context;
	}
	catch (RuntimeException ex) {
		logger.error("Context initialization failed", ex);
		servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
		throw ex;
	}
	catch (Error err) {
		logger.error("Context initialization failed", err);
		servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
		throw err;
	}
}

The integration system of ApplicationContext under spring system

So far, the parent (root) context of Spring has been initialized and already exists in the ServletContext.

  • Loading of spring MVC sub container

The inheritance diagram of dispatcher servlet is as follows

As we know, load the web After the Listener and Filter configured in XML, the Servlet will be loaded. On our web In XML, it is org springframework. web. Servlet. DispatcherServlet. Through the inheritance tree, we know that DispatcherServlet is also the implementation of Servlet, so the loading process is also the process of Servlet. Because the dispatcher Servlet inherits the frameworkservlet, the frameworkservlet inherits the HttpServletBean, and the HttpServletBean inherits the HttpServlet and rewrites the init method, the entry when creating the sub context is in this init method.

  • HttpServletBean.init(): overrides the method in GenericServlet and is responsible for setting ServletConfig to the current Servlet object
public final void init() throws ServletException {
		 //Read init param of Servlet configuration and create dispatcher Servlet instance
		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;
			}
		}
		// Nothing is done in this method of HttpServletBean. The initServletBean () method of the subclass FrameWorkServlet is overridden
       // This class, so the subsequent work will be executed in this method.
		initServletBean();
	}

The following is the initServletBean () method of the FrameWorkServlet class

//FrameWorkServlet.initServletBean()
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 {
        //Here is the key point. Initialize the sub Spring context
		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;
	}
	if (this.logger.isInfoEnabled()) {
		long elapsedTime = System.currentTimeMillis() - startTime;
		this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
				elapsedTime + " ms");
	}
}

The following is the specific code of the initWebApplicationContext () method

protected WebApplicationContext initWebApplicationContext() {
    // <1> Get the root WebApplicationContext object
    WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    // <2> Get WebApplicationContext wac object
    WebApplicationContext wac = null;

    // In the first case, if the constructor has passed in the webApplicationContext attribute, it will be used directly
    if (this.webApplicationContext != null) {
        // A context instance was injected at construction time -> use it
        wac = this.webApplicationContext;
        // If it is of type ConfigurableWebApplicationContext and is not activated, it will be initialized
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            if (!cwac.isActive()) { // not active
                // 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);
                }
                // Configure and initialize wac
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    // In the second case, get the corresponding WebApplicationContext object from ServletContext
    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();
    }
    // Third, create a WebApplicationContext object
    if (wac == null) {
        // No context instance is defined for this servlet -> create a local one
        wac = createWebApplicationContext(rootContext);
    }

    // <3> If the refresh event is not triggered, the refresh event is triggered actively
    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.
        synchronized (this.onRefreshMonitor) {
            onRefresh(wac);
        }
    }

    // <4> Set context to ServletContext
    if (this.publishContext) {
        // Store Spring sub context into ServletContext
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }
    return wac;
}

Finally, take a look at the onRefresh() method in DispatcherServlet, which initializes many policies:
Note: frameworkservlet Onrefresh() can only be overridden in DispatcherServlet

//Initialize nine components
protected void initStrategies(ApplicationContext context) {
	initMultipartResolver(context);
	initLocaleResolver(context);
	initThemeResolver(context);
	initHandlerMappings(context);
	initHandlerAdapters(context);
	initHandlerExceptionResolvers(context);
	initRequestToViewNameTranslator(context);
	initViewResolvers(context);
	initFlashMapManager(context);
}

So far, the start-up process of spring MVC is over. Here is a summary of spring MVC initialization:

  1. HttpServletBean mainly does some initialization work. We will Set the parameters configured in XML to Servlet;
  2. The main function of FrameworkServlet is to initialize Spring sub context, set its parent context, and associate it with ServletContext;
  3. Dispatcher servlet: initializes the implementation classes of various functions. Such as exception handling, view handling, request mapping, etc.

Topics: Front-end Spring xml