How Tomcat works — 七、tomcat发布webapp
目录
- 什么叫发布
- webapp发布方式
- reload
- 总结
什么叫发布
发布就是让tomcat知道我们的程序在哪里,并根据我们的配置创建Context,进行初始化、启动,如下:
- 程序所在的位置
- 创建Context,添加到Host
- 初始化(创建解析webxml的digester)
- 启动(初始化filter、listener、servlet)
webapp发布方式
在tomcat 中发布webapp的方式不同会导致app启动的先后顺序不一样(这里按照启动顺序或者时机不同进行划分):
- 在xml中配置,在conf/server.xml中配置(在host标签内部)
- 直接将webapp文件夹、war包放在tomcat下面的"webapps"目录,或者在webapps下面新建一个xml(根标签为context,在属性中表明应用程序的位置)
其实两种发布方式只是在启动顺序上稍有不同,启动过程完全一致,先以在server.xml中配置说明
在server.xml进行配置
这情况在我们使用eclipse等工具进行开发发布的时候,eclipse会帮我们在server.xml的Host标签内添加Context,如下:
<?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 except in compliance with
the License. You may obtain a copy of the License at 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 particular 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 received
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" redirectPort="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 included with the request, and passes them
on to the appropriate Host (virtual host).
Documentation at /docs/config/engine.html --> <!-- You should 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 performed 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 "%r" %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>
在新建server的时候会解析server.xml,同时也会根据我们上面的配置新建StandardContext,而且会将StandardContext作为Host的一个Child(可以在Catalina.createStartDigester方法中查看怎么解析server.xml),在tomcat的启动过程中context是由父容器host启动的

额,看到这张图发现似曾相识,对滴,就是Context的初始化,因为在tomcat中一个context实例就代表一个webapp,所以其实应用程序webapp的发布本身就是context的初始化和启动,再看看context的启动

以上已经完整展示了一个webapp的发布过程,也就是在server.xml的配置的webapp发布过程,接着来看看在webapps目录下的发布过程。
在webapps目录下
在StandardHost的startInternal方法中调用了父类的ContainerBase.startInternal方法,在StandardHost发布完在server.xml中配置的app之后,会调用setState来切换自身的状态,这个时候就会触发listener HostConfig的lifecycleEvent方法
@Override
protected 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
// 因为在解析server.xml的时候已经新建了Context,这里就可以直接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(); // 调用lifecycleEvent方法,触发StandardHost的start事件,触发监听器HostConfig的start方法,所有在webapps下面的都在start方法中发布
setState(LifecycleState.STARTING); // Start our thread
threadStart(); }
调用过程如下:

(上图中主要画出了deployWars的调用过程,其他两个deploy方法也类似)
在HostConfig.deployApps方法中主要进行了:
- 调用deployDescriptors:发布所有使用xml配置的webapp,因为可能有多个xml,所以在该方法内部又调用了deployDescriptor来发布每个xml对应的webapp
- 调用deployWars:发布所有在webapps目录下的war包,也可能存在多个
- 调用deployDirectories:发布所有直接部署在webapps目录下的应用程序
前面说过了,发布webapp就是新建一个context对象并初始化、启动,上面三个方法中主要的作用为:
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);
- 构建一个StandardContext
- 将context添加到host中,在Container.addChildInternal方法中会调用context.start
接下来的步骤就和上面在server.xml配置的webapp启动一致了。
reload
在我们使用tomcat开发web的时候经常会用到“热加载”(热部署)功能,那么原理究竟是什么呢?上面介绍了webapp发布,因为reload功能也是从HostConfig开始的,所以继续介绍reload功能

上面的ContainerBase.startInternal是由StandardEngine.startInternal方法调用的,启动了一个daemon线程定时检测webapp是否发生变化(文件是否被修改),如果被修改了则会重新启动StandardContext。
总结
像tomcat部署和发布,我们天天都在用,可是不知道究竟原理怎么样的,在学习了tomcat源码之后,对这一切都更加明了。知其然,知其所以然。
How Tomcat works — 七、tomcat发布webapp的更多相关文章
- How Tomcat Works(七)
本文接下来介绍并分析servlet容器,servlet容器是用来处理请求servlet资源,并为web客户端填充response对象的模块. servlet容器是org.apache.catalina ...
- How Tomcat works — 四、tomcat启动(3)
上一节说到StandardService负责启动其子组件:container和connector,不过注意,是有先后顺序的,先启动container,再启动connector,这一节先来看看conta ...
- How Tomcat Works(十八)
在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器.servlet容器.Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来:这种配置应 ...
- How Tomcat Works(十三)
本文分析tomcat容器的安全管理,servlet技术支持通过配置部署描述器(web.xml文件)来对受限内容进行访问控制:servlet容器是通过一个名为验证器的阀来支持安全限制的,当servlet ...
- How Tomcat Works(十一)
本文接下来分析tomcat的类载入器,tomcat需要实现一个自定义的载入器,而不能使用系统类载入器 (1)限制serlvet访问当前运行的java虚拟机中环境变量CLASSPATH指明的路径下的所有 ...
- How Tomcat Works(九)
本文接下来描述servlet容器是怎样管理其相关组件的生命周期的,首先本人描述一下事件监听模式,也可以称为观察者模式,该模式分为以下角色 即抽象主题角色 具体主题角色 抽象观察者角色及具体观察者角色, ...
- 如何修改Tomcat的默认项目发布路径
tomcat默认的项目发布目录是/webapp/ROOT,如果想自定义发布目录,应该怎么办呢? 修改配置文件 首先,修改$tomcat/conf/server.xml文件. 在server.xml文件 ...
- How Tomcat Works(二十)
要使用一个web应用程序,必须要将表示该应用程序的Context实例部署到一个host实例中.在tomcat中,context实例可以用war文件的形式来部署,也可以将整个web应用拷贝到Tomcat ...
- 7、DockerFile案例:自定义centos、自定义tomcat、webapps项目发布
1.Base镜像(scratch) Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的 2.自定义镜像mycentos 1.Hub默认CentOS镜像什 ...
随机推荐
- Sphinx中文分词详细安装配置及API调用实战
这几天项目中需要重新做一个关于商品的全文搜索功能,于是想到了用Sphinx,因为需要中文分词,所以选择了Sphinx for chinese,当然你也可以选择coreseek,建议这两个中选择一个,暂 ...
- 实现公告栏无缝滚动的js代码(转)
<!DOCTYPE HTML> <html> <head> <meta charset="gb2312" /> <title& ...
- EhReport ,CReport改进版本,再次改进 ,V1.31
取消了xlgrid依赖,带齐了第三方包. 安装更加方便. For D7 下载源码
- 【转载】PHP.INI配置:Session配置详细说明教程
网上有很多PHP.INI文件配置的中文说明,但是对于PHP初学者来说在进行PHP运行环境搭建配置时还是容易一头雾水,今天换一种角度来分享如何进行php.ini配置,以求达到解决实际问题的效果,开篇以P ...
- LeetCode:Permutations, Permutations II(求全排列)
Permutations Given a collection of numbers, return all possible permutations. For example, [1,2,3] h ...
- Remove Linked List Elements
Remove all elements from a linked list of integers that have value val. ExampleGiven: 1 --> 2 --& ...
- Web大文件上传控件-asp.net-bug修复-Xproer.HttpUploader6.2
版权所有 2009-2016荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webapp/up6.2/in ...
- Ubuntu远程开机 (Wake on Lan)
启动者(A) 被远程开启者(B) 一.被远程开启的电脑(电脑B):1. 重新开机,并进到BIOS设定2. 把Wake On Land / Wake On PCI(E)设为Enable3. 储存并进入U ...
- python+图像分割seg
好痛苦 1.目前思路为HOG+SVM 提取HOG时候发现,包装的lib cv2 里有hog算子,但是函数是指针形式.不会用了.. 现在改用推荐的scikits.image , from skimage ...
- Spring MVC静态资源处理(在applicationContex.xml文件中进行配置)
优雅REST风格的资源URL不希望带 .html 或 .do 等后缀.由于早期的Spring MVC不能很好地处理静态资源,所以在web.xml中配置DispatcherServlet的请求映射,往往 ...