An overview of the

If you’re familiar with how Tomcat loads Spring and SpringMVC, we’re going to go through the process today.

There will be a lot of knowledge involved, including design patterns at load time, Servlet knowledge, etc. You will definitely learn something from this

This article first personal public account: Java Architect Federation, updated daily technical good articles

Tomcat

Tomcat is a Web application server written in Java. It is also called a Web container for running Web programs

Tomcat startup

When tomcat is started, it generates a Jvm (Java Virtual Machine) process in the operating system that listens for HTTP/1.1 messages from the configuration listening port (default 8080)

The default configuration file looks like this

When Tomcat is started, it will load the webapps projects in its installation directory (war packages will automatically decompress into projects).

Q: Do multiple projects in Webapps run on the same JVM

Is running on the same JVM (the one created when Tomcat was started), multiple projects are multiple threads, and data is not shared between projects because the class loaders are different

Loading Web applications (Spring+SpringMVC Framework)

After Tomcat is started, the most important thing is to generate a ServletContext (Tomcat’s context), which will then load the project based on the web.xml in the WebApps project

Here is a partial web.xml for a SpringMVC+Spring project

<! Here is the configuration required to load Spring --> <! <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:applicationContext.xml </param-value> </context-param> <! - Spring start classes - > < listener > < listener - class > org. Springframework. Web. Context. ContextLoaderListener < / listener - class > </listener> <! <servlet> <servlet-name>project</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <! The order in which servlets are loaded, The smaller the value, the higher the priority (positive number) --> <servlet-mapping> <servlet-name>project</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> </servlet>Copy the code

Initialize the Spring

Tomcat first loads ContextLoaderListener and then injects parameters written in applicationContext.xml to complete a series of Spring initializations (beans, database resources, etc.).

Here is the oft-heard Ioc container initialization. We searched this class and found the following code

Public Class ContextLoaderListener extends ContextLoader implements ServletContextListener {** * Initialize the root web application context. */ @Override public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); } // omit other methods}Copy the code

The most important thing here is to initialize the Spring-owned WebApplicationContext with the ServletContext and store it in the ServletContext

How important WebApplicationContext brother know, we often use WebApplicationContext. The getBean () to obtain the Spring management classes, so this is also the core of the IOC container

The way Spring uses this listener to launch itself is also a design pattern called observer mode:

The whole process works like this. When Tomcat loads a Webapps project, it first loads the classes indicated in web.xml by reflection (all in an array).

At some point, I tomcat (event source, event origin) will issue an event called ServletContextEvent (with various parameters)

For any class that implements the ServletContextListener interface, I call the contextInitialized method and pass in the event parameter

Ok, so now I’m going to see if there’s anything in the array that matches the criteria, and I’m going to call the contextInitialized method if I find something that actually implements this interface

Spring is loaded dynamically

An aside:

To load a Class, you can use the full Class name, which is loaded by Java reflection, class.forname.

You can also load a new class directly

The initialization for SpringMVC

If we look at the configuration file, it’s labeled servlet, so we have to first understand what a servlet is

Introduction of the Servlet

A Servlet is an interface designed for Web communication (basically, a bunch of sun executives meeting to create classes with fixed methods).

Tomcat has a set of defined programs (not only Tomcat, but also web application servers that can run Java, such as Jetty, etc.)

1. When Tomcat loads a class that implements the Servlet interface, it registers it in a Map and executes an init() method to initialize the Servlet

2. When Tomcat receives a browser request, it searches the Map for the Servlet corresponding to the path, which is the parameter written in the label, and calls the service() method

3. When the Servlet is about to be destroyed, call the destroy() method once

Spring loading is similar to Spring loading, which is implemented after an interface is arranged by fate (Tomcat) ~~

Of course, we have too much trouble implementing the Servlet interface ourselves, so HttpServlet (an abstract class) implements most of the methods for us (including HTTP header Settings, doXXX method judgments, etc.).

So we can just inherit HttpServlet and implement a few methods

For SpringMVC load

Why servlets, because the heart of SpringMVC is the DispatcherServlet (front controller), as shown

The DispatcherServlet is implemented by SpringMVC and is already well implemented so we don’t need to touch it anymore

Tomcat loads the DispatcherServlet from web.xml and then calls its init() method

The Servlet configuration file defaults to/web-INF /-servlet.xml, so it is now called project-servlet.xml by default

Of course, you can also specify your own files

<! <servlet> <servlet-name>project</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <! --> <init-param> <param-name>contextCOnfigLocation</param-name> <param-value>classPath:spring-servlet.xml</param-value> </init-param> <servlet-mapping> <servlet-name>project</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> </servlet>Copy the code

When SpringMVC is loaded and a browser request comes in, if it ends in.html, Tomcat will hand it over to a DispatcherServlet

The DispatcherServlet will find the corresponding processor according to the path, which can be understood as the Controller we wrote received (specific SpringMVC process will write a blog post).

At this point, the browser sends the request, and the process ends when we execute the code we’ve written

Spring and SpringMVC container issues

Since we are talking about tomcat loading these two frameworks, do you notice that in web.xml, Spring loading is written before DispatcherServlet loading

Let’s take a look at the initialization method of DispatcherServlet. Since DispatcherServlet is inherited from each layer, the initialization method also becomes

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {// other methods @override public final void init() throws ServletException {// other code // Let subclasses do whatever initialization they like. initServletBean(); } protected void initServletBean() throws ServletException {} public Abstract Class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {// Other methods @override protected final void initServletBean() throws ServletException try {{/ / other code enclosing webApplicationContext = initWebApplicationContext (); initFrameworkServlet(); } catch (ServletException | RuntimeException ex) { logger.error("Context initialization failed", ex); throw ex; Other code}} / / protected WebApplicationContext initWebApplicationContext () {/ / get the Spring to create WebApplicationContext, Key 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); / / set the parent context} configureAndRefreshWebApplicationContext (cwac); }} // other code} // other methods}Copy the code

As you can see, the HttpServlet implements init(), leaving the initServletBean() abstract method behind

And realized FrameworkServlet initServletBean () method is defined as the final (rewrite) are not allowed. In this method calls the initWebApplicationContext ()

And initWebApplicationContext () illustrates the if found in tomcat webapplication, get it, and then set it to for SpringMVC parent context

Now the DispatcherServlet initialization is complete (of course I omitted the other initialization things)

So there is a parent-child relationship between Spring and SpringMVC containers, and since the child can access the contents of the parent and not the other way around, don’t think about automating Controller operations in a Service

So here’s what happens

What if Controller is also swept in the Spring configuration

<? The XML version = "1.0" encoding = "utf-8"? > <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" ..... / here omitted > <! <context:component-scan base-package="com.shop"></context:component-scan> <! ><! - <! <context:component-scan base-package="com.shop. Service "></context:component-scan>> </beans>Copy the code

So the Controller will go into the Spring context, there will be no Controller in the SpringMVC, and then when there is a request to the DispatcherServlet, the Controller will not be found and 404

Q: Can SpringMVC scan all packages

This is ok, SpringMVC can be used without Spring, but it was added to make it more compatible with other frameworks (database frameworks, etc.)

But if you’re using Spring you can’t do that, and Spring sweeps the Controller, SpringMVC sweeps the Controller, and all sorts of weird things happen