Foreword:
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 each Jar 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 for processing, and we can focus more on business logic. However, knowing the working principle of Tomcat and processing the request process 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.
Tomcat overall architecture
Tomcat is a free, open source, lightweight web application server. It is suitable for use in small and medium-sized enterprises projects where the concurrency is not very high.
File directory structure
The following is the main directory structure of Tomcat 8:
Functional component structure
There are two core functions of Tomcat, namely the Connector which is responsible for receiving and feeding back external requests, and the Container which is responsible for processing requests. The connector and the container complement each other and together constitute the basic web service Service. Each Tomcat server can manage multiple Services.
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 a 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: Engine, Host, Context and Wrapper, and finally executes the corresponding business logic 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 point, 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">
<!-- 连接器监听端口是 8080,默认通讯协议是 HTTP/1.1 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- 名字为 Catalina 的引擎,其默认的虚拟主机是 localhost -->
<Engine name="Catalina" defaultHost="localhost">
<!-- 名字为 localhost 的虚拟主机,其目录是 webapps-->
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
</Host>
</Engine>
</Service>
</Server>
How SpringBoot starts 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 for 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 to 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
Conclusion
This is the end of the sorting process. If you need more Java learning materials or the latest Java interview materials compiled in 2020, you can click to enter, the code: cszq , you can provide learning materials and ways for free!
Finally, I wish you all the best in your work!