SpringBoot is like a python, slowly winding around us, paralyzing us. Admittedly, using SpringBoot does improve productivity, but it also makes us forget a lot of skills. When I first started out, I used Tomcat to manually deploy JavaWeb projects and often tuned Tomcat for performance. In addition, you need to clarify the relationship between jars to avoid Jar loss and service startup exceptions caused by version conflicts. Now that the tedious and repetitive work has been handed over to SpringBoot, we can focus more on business logic. However, understanding how Tomcat works and how requests are processed is just as important as analyzing the source code of the Spring framework. At least interviewers love to ask about these underlying principles and design ideas. Hopefully this article will give you some help.
Functional component structure
Core principles of the Tomcat connector
Tomcat connector framework — Coyote
Connector Core Functions
1. Monitor network ports to receive and respond to network requests.
Second, network byte stream processing. The received network byte flow is converted into Tomcat Request and then converted into a standard ServletRequest to the container. Meanwhile, the ServletResponse from the container is converted into Tomcat Response and then converted into network byte stream.
Connector module design
To meet the two core functions of the connector, we need a communication endpoint to listen on the port; A processor is needed to process the network byte stream; Finally, an adapter is required to transform the processed results into the structure needed by the container.
The corresponding source package path is org.apache.coyote. The corresponding structure is shown as follows
Core principles of the Tomcat container
Tomcat container Framework — Catalina
Container structure analysis
Each Service contains a container. Container can manage multiple virtual hosts by a single engine. Each virtual host can manage multiple Web applications. Each Web application has multiple Servlet wrappers. Engine, Host, Context, and Wrapper are parent-child containers.
The corresponding source package path is org.apache.coyote. The corresponding structure is shown as follows
Container request processing
The request processing of the container is layered between Engine, Host, Context, and Wrapper, and the corresponding business logic is executed in the Servlet. Each container has a channel Pipeline, and each channel has a Basic Valve (such as StandardEngineValve), which acts as a gate for processing Request and Response. The flow chart is as follows.
Tomcat request processing process
The above points have provided a piecemeal overview of how Tomcat handles a request. The process of connector + process of container = Process of Tomcat. Ha! Ha! The question is, how does Tomcat find the corresponding virtual site through the request path? How do I find the corresponding Servlet?
This section describes the functions of the mapper
There is a component called Mapper that needs to be introduced that is not covered above. As the name implies, it provides a routing map of the request path. Depending on which container the request URL address match is handled. Each container has its own Mapper, such as MappedHost. I don’t know if you recall being at the mercy of Mapper Class Not Found. In the past, mapping rules had to be configured in web.xml every time a complete function was written, and as the file grew larger, problems arose
HTTP Request Process
Open the tomcat/conf directory server. The XML file to analyze a request to http://localhost:8080/docs/api.
Step 1: The connector listens on port 8080. Because the requested port is the same as the listening port, the connector accepts the request.
Step 2: Because the engine’s default virtual host is localhost and the directory of the virtual host is Webapps. So the request finds the Tomcat/Webapps directory.
Step 3: The parsed docs is the application name of the Web application, the context. At this point the request continues to find the docs directory from the Webapps directory. Sometimes we omit the name of the application.
Step 4: The PARsed API is the specific business logic address. At this point, you need to find the mapping from docs/ web-INF /web.xml, and then call the specific function.
<? The XML version = "1.0" encoding = "utf-8"? > <Server port="8005" shutdown="SHUTDOWN"> <Service name="Catalina"> <! -- Connector listening port is 8080, /> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <! <Engine name="Catalina" defaultHost="localhost"> <! -- virtual host with name localhost, <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> </Host> </Engine> </Service> </Server>Copy the code
How does SpringBoot start embedded Tomcat
SpringBoot one-click start service function, let a lot of friends who just entered the society forget what Tomcat is. With the increasing performance of hardware, common small and medium projects can be directly started with the built-in Tomcat. However, some larger projects may use Tomcat clustering and tuning, and the built-in Tomcat may not be sufficient.
SpringBoot 2. X is the source code for Tomcat.
The code starts with the main method and executes the run method to start the project.
SpringApplication.run
Copy the code
Click on 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);
Copy the code
Click on the Refresh Context method and find the refresh method. And find the method of its parent class.
this.refresh(context);
Copy the code
In the refresh method of AbstractApplicationContext classes, there was a row of child containers flush the logic.
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
Copy the code
Find ServletWebServerApplicationContext onRefresh approach into, the realization method. Here, at last, there is hope.
protected void onRefresh() { super.onRefresh(); try { this.createWebServer(); } catch (Throwable var2) { throw new ApplicationContextException("Unable to start web server", var2); }}Copy the code
Click on the createWebServer method to find the code to get WebServer from the factory class.
if (webServer == null && servletContext == null) { ServletWebServerFactory factory = this.getWebServerFactory(); / / access to the web server. This webServer = factory. GetWebServer (new ServletContextInitializer [] {enclosing getSelfInitializer ()}); } else if (servletContext ! = null) {try {// Start web server this.getSelfinitializer ().onstartup (servletContext); } catch (ServletException var4) { throw new ApplicationContextException("Cannot initialize servlet context", var4); }}Copy the code
Find TomcatServletWebServerFactory getWebServer approach, the implementation method, and the matching and Jetty and Undertow. Basic connectors, engines, virtual sites, and so on 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); }Copy the code
Logs are generated after the service is started
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.C atalina. 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 msCopy the code
I feel I seem to find why the more cattle companies will ask the underlying source code of technology, because in the process of looking at the source code is really interesting, and can find a lot of problems, and really is a test of logical thinking and patience, I look at the Tomcat source code, a day so the past, not yet finished, This is still on the premise that I think I am already very familiar with Tomcat. Haha, follow me and update slowly when you have time later
Finally to introduce you to a document, which I also in the process of resolving the tomcat reference books, most of internal knowledge basic covers tomcat related content, from the architecture design to the configuration to the cluster to performance optimization and extension, omni-directional analytical tomcat, friends in need can be focused on + after forwarding, direct messages “source” can view the access
Tomcat architecture
Tomcat Configuration Management
Tomcat security
Tomcat tuning
Additional Tomcat features
Length reasons, only show this part, there is a need for more Java related learning documents, video, pay attention to me, background private letter “information” can be obtained