How Tomcat works-7. tomcat releases webapp and tomcatwebapp
Directory
- What is publishing?
- Webapp publishing Method
- Reload
- Summary
What is publishing?
Publishing is to let tomcat know where our program is, and create a Context according to our configuration for initialization and startup, as shown below:
- Location of the program
- Create Context and add it to Host
- Initialize (create a digester to parse webxml)
- Start (initialize filter, listener, servlet)
Webapp publishing Method
Different webapp publishing methods in tomcat may lead to different app startup sequence (which is divided by startup sequence or timing ):
In fact, the two release methods are slightly different in the startup sequence, and the startup process is exactly the same. The configuration instructions in server. xml are described first.
Configure in server. xml
In this case, when we use eclipse and other tools for development and release, eclipse will help us add Context in the Host tag of server. xml, as shown below:
<? Xml version = "1.0" encoding = "UTF-8"?> <! -- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. see the NOTICE file distributed with this work for additional information regarding copyright ownership. the ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file License t in compliance with the License. you may obtain a copy of the License Http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "as is" BASIS, without warranties or conditions of any kind, either express or implied. see the License for the specific language governing permissions and limitations under the License. --> <! -- Note: A "Server" is not itself a "Container", so you may not define subcomponents such as "Valves" at this level. documentation at/docs/config/server.html --> <Server port = "8006" shutdown = "SHUTDOWN"> <Listener className = "org. apache. catalina. startup. versionLoggerListener "/> <! -- Security listener. Documentation at/docs/config/listeners.html <Listener className = "org. apache. catalina. security. SecurityListener"/> --> <! -- APR library loader. Documentation at/docs/apr.html --> <Listener SSLEngine = "on" className = "org. apache. catalina. core. AprLifecycleListener"/> <! -- Initialize Jasper prior to webapps are loaded. Documentation at/docs/jasper-howto.html --> <Listener className = "org. apache. catalina. core. JasperListener"/> <! -- Prevent memory leaks due to use of particle java/javax APIs --> <Listener className = "org. apache. catalina. core. jreMemoryLeakPreventionListener "/> <Listener className =" org. apache. catalina. mbeans. globalResourcesLifecycleListener "/> <Listener className =" org. apache. catalina. core. threadLocalLeakPreventionListener "/> <! -- Global JNDI resources Documentation at/docs/jndi-resources-howto.html --> <GlobalNamingResources> <! -- Editable user database that can also be used by UserDatabaseRealm to authenticate users --> <Resource auth = "Container" description = "User database that can be updated and saved" factory = "org. apache. catalina. users. memoryUserDatabaseFactory "name =" UserDatabase "pathname =" conf/tomcat-users.xml "type =" org. apache. catalina. userDatabase "/> </GlobalNamingResources> <! -- A "Service" is a collection of one or more "Connectors" that share a single "Container" Note: A "Service" is not itself a "Container ", so you may not define subcomponents such as "Valves" at this level. documentation at/docs/config/service.html --> <Service name = "Catalina"> <! -- The connectors can use a shared executor, you can define one or more named thread pools --> <! -- <Executor name = "tomcatThreadPool" namePrefix = "catalina-exec-" maxThreads = "150" minSpareThreads = "4"/> --> <! -- A "Connector" represents an endpoint by which requests are already ed and responses are returned. documentation at: Java HTTP Connector:/docs/config/http.html (blocking & non-blocking) Java AJP Connector:/docs/config/ajp.html APR (HTTP/AJP) Connector: /docs/apr.html Define a non-ssl http/1.1 Connector on port 8080 --> <Connector connectionTimeout = "20000" port = "8888" protocol = "HTTP/1.1" redirect Port = "8445"/> <! -- A "Connector" using the shared thread pool --> <! -- <Connector executor = "tomcatThreadPool" port = "8080" protocol = "HTTP/1.1" connectionTimeout = "20000" redirectPort = "8443"/> --> <! -- Define a ssl http/1.1 Connector on port 8443 This connector uses the BIO implementation that requires the JSSE style configuration. when using the APR/native implementation, the OpenSSL style configuration is required as described in the APR/native documentation --> <! -- <Connector port = "8443" protocol = "org. apache. coyote. http11.Http11Protocol "maxThreads =" 150 "SSLEnabled =" true "scheme =" https "secure =" true "clientAuth =" false "sslProtocol =" TLS "/> --> <! -- Define an AJP 1.3 Connector on port 8009 --> <Connector port = "8019" protocol = "AJP/1.3" redirectPort = "8443"/> <! -- An Engine represents the entry point (within Catalina) that processes every request. the Engine implementation for Tomcat stand alone analyzes the HTTP headers encoded with the request, and passes them on to the appropriate Host (virtual host ). documentation at/docs/config/engine.html --> <! -- You shoshould set jvmRoute to support load-balancing via AJP ie: <Engine name = "Catalina" defaultHost = "localhost" jvmRoute = "jvm1"> --> <Engine defaultHost = "localhost" name = "Catalina"> <! -- For clustering, please take a look at documentation at:/docs/cluster-howto.html (simple how to)/docs/config/cluster.html (reference documentation) --> <! -- <Cluster className = "org. apache. catalina. ha. tcp. SimpleTcpCluster"/> --> <! -- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className = "org. apache. catalina. realm. LockOutRealm"> <! -- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase ". any edits that are stored med against this UserDatabase are immediately available for use by the Realm. --> <Realm className = "org. apache. catalina. realm. userDatabaseRealm "resourceName =" UserDatabase "/> </Realm> <Host appBase =" webapps "autoDeploy =" true "name =" localhost "unpackWARs =" true "> <! -- SingleSignOn valve, share authentication between web applications Documentation at:/docs/config/valve.html --> <! -- <Valve className = "org. apache. catalina. authenticator. SingleSignOn"/> --> <! -- Access log processes all example. documentation at:/docs/config/valve.html Note: The pattern used is equivalent to using pattern = "common" --> <Valve className = "org. apache. catalina. valves. accessLogValve "directory =" logs "pattern =" % h % l % u % t & quot; % r & quot; % s % B "prefix =" localhost_access_log. "suffix = ". txt "/> <Context docBase ="/var/tomcat-test/webapps/TestTomcat "path ="/TestTomcat "reloadable =" true "source =" org. eclipse. jst. jee. server: TestTomcat "/> </Host> </Engine> </Service> </Server>View Code
The server will be parsed when the server is created. xml, StandardContext will also be created based on the above configuration, and StandardContext will be used as a Child of the Host (can be found in Catalina. in the createStartDigester method, check how to parse the server. xml), context is started by the parent container host during tomcat startup.
Yes, I see this figure and it seems like I have known each other. This is the initialization of Context, because a context instance in tomcat represents a webapp, in fact, the publishing of the application webapp itself is the initialization and startup of context. Let's look at the startup of context.
The above shows the publishing process of a webapp, that is, the webapp publishing process configured in server. xml. Let's take a look at the publishing process under the webapps directory.
Under the webapps directory
The ContainerBase of the parent class is called in the startInternal method of StandardHost. startInternal method. After StandardHost is released. after the app is configured in xml, setState is called to switch its own State. This will trigger the lifecycleEvent method of listener HostConfig.
@ Overrideprotected synchronized void startInternal () throws LifecycleException {// Start our subordinate components, if any if (loader! = Null) & (loader instanceof Lifecycle) (Lifecycle) loader). start (); logger = null; getLogger (); if (manager! = Null) & (manager instanceof Lifecycle) (Lifecycle) manager). start (); if (cluster! = Null) & (cluster instanceof Lifecycle) (Lifecycle) cluster). start (); Realm realm = getRealmInternal (); if (realm! = Null) & (realm instanceof Lifecycle) (Lifecycle) realm). start (); if (resources! = Null) & (resources instanceof Lifecycle) (Lifecycle) resources). start (); // Start our child containers, if any
// Because the server is being parsed. the Context has been created in xml. Here, you can directly start Container children [] = findChildren (); list <Future <Void> results = new ArrayList <Future <Void> (); for (int I = 0; I <children. length; I ++) {results. add (startStopExecutor. submit (new StartChild (children [I]);} boolean fail = false; for (Future <Void> result: results) {try {result. get ();} catch (Exception e) {log. error (sm. getString ("containerBase. threadedStartFailed "), e); fail = true ;}} if (fail) {throw new LifecycleException (sm. getString ("containerBase. threadedStartFailed ");} // Start the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle) (Lifecycle) pipeline ). start (); // call the lifecycleEvent method to trigger the start event of StandardHost and trigger the start method of the listener HostConfig. setState (LifecycleState) is released in the start method under webapps. STARTING); // Start our thread threadStart ();}
The call process is as follows:
(This mainly draws the call process of deployWars, and the other two deploy methods are similar)
In HostConfig. deployApps:
- Call deployDescriptors: publish all webapps configured using xml. because there may be multiple xml files, deployDescriptor is called internally to publish the webapp corresponding to each xml file.
- Call deployWars: release all war packages in the webapps directory. There may also be multiple
- Call deployDirectories to publish all applications directly deployed in the webapps directory.
As mentioned above, publishing webapp is to create a context object and initialize and start it. The main functions of the preceding three methods are as follows:
Class<?> clazz = Class.forName(host.getConfigClass());LifecycleListener listener = (LifecycleListener) clazz.newInstance();context.addLifecycleListener(listener);context.setName(cn.getName());context.setPath(cn.getPath());context.setWebappVersion(cn.getVersion());context.setDocBase(cn.getBaseName() + ".war");host.addChild(context);
- Build a StandardContext
- Add context to host. In the Container. addChildInternal method, context. start is called.
The subsequent steps are consistent with the webapp startup configured in server. xml.
Reload
When we use tomcat to develop the web, we often use the "Hot load" (hot deployment) function. What is the principle? The previous section introduced the release of webapp. Because the reload function starts from HostConfig, we will continue to introduce the reload function.
The above ContainerBase. startInternal is composed of StandardEngine. when the startInternal method is called, a daemon thread is started to regularly check whether the webapp is changed (whether the file is modified). If it is modified, StandardContext is restarted.
Summary
We use tomcat for deployment and release every day, but we don't know how it works. after learning the tomcat source code, we have made it clearer. Knowing and knowing why.