SpringBoot is like a giant python, slowly entwining us and paralyzing us. I have to admit that using SpringBoot does improve work efficiency, but it also makes us forget a lot of skills. When I first entered the society, I still manually deployed JavaWeb projects through Tomcat, and often performed performance tuning on Tomcat. In addition, you also need to clarify the relationship between the Jars yourself to avoid the problem of abnormal service startup caused by Jar loss and version conflicts. Up to now, these tedious and repetitive tasks have all been handed over to SpringBoot, and we can focus more on business logic. However, understanding the working principle of Tomcat and the process of processing requests is as important as analyzing the source code of the Spring framework. At least the interviewer likes to ask about these underlying principles and design ideas. Hope this article can give you some help.
Functional component structure
The core principle of Tomcat connector
Tomcat connector framework-Coyote
Connector core functions
1. Monitor network ports, receive and respond to network requests.
2. Network byte stream processing. Convert the received network byte stream into a Tomcat Request and then into a standard ServletRequest to the container, and at the same time convert the ServletResponse from the container into a Tomcat Response and then into a network byte stream.
Connector module design
In order to meet the two core functions of the connector, we need a communication endpoint to monitor the port; a processor to process the network byte stream; and finally an adapter to convert the processed result into the structure required by the container.
The corresponding source code package path org.apache.coyote. The corresponding structure diagram is as follows
The core principle of Tomcat container
Tomcat container framework-Catalina
Container structure analysis
Each Service will contain a container. The container can manage multiple virtual hosts by one engine. Each virtual host can manage multiple web applications. Each web application will have multiple servlet wrappers. Engine, Host, Context and Wrapper, the four containers belong to the parent-child relationship.
The corresponding source code package path org.apache.coyote. The corresponding structure diagram is as follows
Container request processing
The request processing process of the container is called layer by layer among the four containers of Engine, Host, Context and Wrapper, and finally the corresponding business logic is executed in the Servlet. Each container will have a channel Pipeline, and each channel will have a Basic Valve (such as StandardEngineValve), which is similar to a gate used to process Request and Response. The flow chart is as follows.
Tomcat request processing flow
The above knowledge points have introduced piecemeal how a Tomcat handles a request. A simple understanding is that the processing flow of the connector + the processing flow of the container = the processing flow of Tomcat. what! So the question is, how does Tomcat find the corresponding virtual site through the request path? How to find the corresponding Servlet?
Mapper function introduction
Here you need to introduce a component Mapper that is not described above. As the name suggests, its role is to provide a route map of the request path. According to the request URL address matching is handled by which container. Each of these containers will have its own corresponding Mapper, such as MappedHost. I don’t know if you recall the fear of being dominated by Mapper class not found. In the past, every time you write a complete function, you need to configure the mapping rules in web.xml. When the file becomes larger and larger, various problems will also appear.
HTTP request flow
Open the server.xml file in the tomcat/conf directory to analyze a http://localhost:8080/docs/api request.
Step 1: The listening port of the connector is 8080. Since the requested port is the same as the listening port, the connector accepted the request.
Step 2: Because the default virtual host of the engine is localhost, and the directory of the virtual host is webapps. So the request found the tomcat/webapps directory.
Step 3: The parsed docs is the application name of the web program, which is the context. At this time, the request continues to find the docs directory under the webapps directory. Sometimes we also omit the application name.
Step 4: The parsed api is the specific business logic address. At this time, you need to find the mapping relationship from docs/WEB-INF/web.xml, and finally call the specific function.
<?xml version="1.0" encoding="UTF-8"?> <Server port="8005" shutdown="SHUTDOWN"> <Service name="Catalina"> <!-- The connector listening port is 8080, the default The communication protocol is HTTP/1.1 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- The engine named Catalina, its default virtual host It is localhost --> <Engine name="Catalina" defaultHost="localhost"> <!-- The virtual host named localhost, and its directory is webapps--> <Host name="localhost" appBase="webapps" unpackWARs= "true" autoDeploy="true"> </Host> </Engine> </Service> </Server>
How does SpringBoot start the embedded Tomcat
SpringBoot's one-click service start function makes many friends who have just entered the society forget what Tomcat is. With the increasing performance of hardware, ordinary small and medium projects can be started directly with the built-in Tomcat. But some larger projects may use Tomcat clustering and tuning, the built-in Tomcat may not be able to meet the needs.
We first analyze how SpringBoot starts Tomcat from the source code. The following is the code of SpringBoot 2.x.
The code starts from the main method and executes the run method to start the project.
SpringApplication.run
Click in from the run method to find a way to refresh the application context.
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments);
Click in from the refreshContext method and find the refresh method. And look up the method of its parent class layer by layer.
this.refresh(context);
In the refresh method of the AbstractApplicationContext class, there is a line of logic to call the refresh of the child container.
this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh();
Click in from the onRefresh method to find the implementation method of ServletWebServerApplicationContext. Here I finally see hope.
protected void onRefresh() { super.onRefresh(); try { this.createWebServer(); } catch (Throwable var2) { throw new ApplicationContextException("Unable to start web server", var2); } }
Click in from the createWebServer method and find the code to get the WebServer from the factory class.
if (webServer == null && servletContext == null) { ServletWebServerFactory factory = this.getWebServerFactory(); // 获取 web server this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()}); } else if (servletContext != null) { try { // 启动 web server this.getSelfInitializer().onStartup(servletContext); } catch (ServletException var4) { throw new ApplicationContextException("Cannot initialize servlet context", var4); } }
Click in from the getWebServer method and find the implementation method of TomcatServletWebServerFactory, which corresponds to Jetty and Undertow. The basic connector, engine, virtual site and other configurations are configured here.
public WebServer getWebServer(ServletContextInitializer... initializers) { Tomcat tomcat = new Tomcat(); File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat"); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); tomcat.getService().addConnector(connector); this.customizeConnector(connector); tomcat.setConnector(connector); tomcat.getHost().setAutoDeploy(false); this.configureEngine(tomcat.getEngine()); Iterator var5 = this.additionalTomcatConnectors.iterator(); while(var5.hasNext()) { Connector additionalConnector = (Connector)var5.next(); tomcat.getService().addConnector(additionalConnector); } this.prepareContext(tomcat.getHost(), initializers); return this.getTomcatWebServer(tomcat); }
The log will be printed after the service starts
o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8900 (http) o.apache.catalina.core.StandardService : Starting service [Tomcat] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.34 o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal ... o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 16858 ms
I feel as if I have discovered why the most powerful companies ask about the underlying source code of the technology, because the process of looking at the source code is really interesting, and many problems can be found, and it really tests logical thinking and patience. I Let’s look at the tomcat source code. One day has passed, and it’s not finished yet. This is the premise that I thought I was already very familiar with tomcat. Hahahaha, pay attention to me. I will update it later when I have time.
Finally, I will introduce a document to you. This is also the book I refer to most in the process of analyzing tomcat. The internal knowledge basically covers the related content of tomcat, from architecture design to configuration to clustering to performance optimization and expansion, etc., comprehensive analysis of tomcat , Friends in need can follow + after forwarding, private message "source code" to view the acquisition method
tomcat architecture
tomcat configuration management
tomcat security
tomcat tuning
tomcat additional features
For space reasons, only this part is shown. If you need more Java-related learning documents and videos, follow me, and you can get it by private messaging "data" in the background
Public number: Java Architects Alliance, good article on media update technology