这篇文章参考这两篇博客:
1、https://blog.csdn.net/fjslovejhl/article/details/21107331?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163749113016780265445730%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163749113016780265445730&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-8-21107331.pc_v2_rank_blog_default&utm_term=tomcat&spm=1018.2226.3001.4450
2、https://blog.csdn.net/flybone7/article/details/106175068
还有一本书叫《深入刨析Tomcat》,非常棒的一本书,推荐阅读
基本原理1.调用org.apache.catalina.startup.Bootstrap中的主函数main(),main() 中调用自身的start()方法,在start()方法中实例化org.apache.catalina.startup.Catalina类调用其start()方法,在Catalina的start()中调用load()载入tomcat文件夹目录下conf文件夹下的server.xml并创建Server类,然后调用Server的start()方法,到这里我们的tomcat就运行起来了.总的来说就是BootStrap类实例化了Catalina类,然后该Catalina实例解析server.xml里的配置启动Tomcat。
2.Server类代表整个Tomcat服务器,这里有必要介绍一下为什么Tomcat叫Servlet容器,在Tomcat中包含四个容器,分别为Engine,Host,Context,Wrapper.Engine是Host的父容器,依次类推.四者都继承自Container接口.一般在Tomcat中一个Engine实例中包含一个Host实例,一个Host实例中包含一个Context实例,一个Context代表一个WEB程序并包含多个Wrapper实例,一个Wrapper代表一个Servlet类.
3.一次请求的大题流程是这样的,首先由Connector获取到Http请求,封装ServletRequest和ServletResponse对象并派发给Context管道中的所有Valve,执行完所有Valve后执行基础Valve根据请求的url映射到对应的Wrapper,然后调用个Wrapper管道中的所有Valve,最后调用基础Valve在这个Wrapper类所封装的Servlet,实例化后调用其Service方法对用户的请求进行处理,最后将结果负载在response中返回给用户.
大体步骤1、BootStrap启动main方法,tomcat的启动入口
2、bootstrap启动Catalina类
3、Catalina类创建Server实例
4、Server实例调用Service类启动
5、Service类让engine启动,engine是tomcat的顶级容器接口,tomcat根据lifecycle机制让顶级接口启动的同时把子接口也启动。
6、engine启动,触发start事件,监听器触发各个组件启动
7、tomcat启动完毕
Server对象的创建 BootStrap实例化Catalina类public static void main(String args[])
{
if (daemon == null)
{
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try
{
bootstrap.init();
} catch (Throwable t)
{
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else
{
// When running as a service the call to stop will be on a new
// thread so make sure the correct class loader is used to prevent
// a range of class not found exceptions.
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
try
{
//这里的设置默认的命令为start
String command = "start";
if (args.length > 0)
{
//解析实际上的命令行参数
command = args[args.length - 1];
}
if (command.equals("startd"))
{
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd"))
{
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start"))
{
// 在这里读取命令行参数为start,然后启动。
daemon.setAwait(true);
daemon.load(args);
daemon.start();
} else if (command.equals("stop"))
{
daemon.stopServer(args);
} else if (command.equals("configtest"))
{
daemon.load(args);
if (null == daemon.getServer())
{
System.exit(1);
}
System.exit(0);
} else
{
log.warn("Bootstrap: command "" + command + "" does not exist.");
}
} catch (Throwable t)
{
// Unwrap the Exception for clearer error reporting
if (t instanceof InvocationTargetException && t.getCause() != null)
{
t = t.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}
实际上main方法从这个里实例化Catalina对象
bootstrap.init();
追进去init()方法看看
public void init() throws Exception {
initClassLoaders();
Thread.currentThread().setContextClassLoader(catalinaLoader);
SecurityClassLoad.securityClassLoad(catalinaLoader);
// Load our startup class and call its process() method
if (log.isDebugEnabled())
log.debug("Loading startup class");
//下面这几行代码就是通过反射创建了Catalina的实例
Class> startupClass =
catalinaLoader.loadClass
("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();
// Set the shared extensions class loader
if (log.isDebugEnabled())
log.debug("Setting startup class properties");
String methodName = "setParentClassLoader";
Class> paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
//把这个实例赋值给BootStrap的成员变量catalinaDaemon
catalinaDaemon = startupInstance;
}
Debug
init()实例化Catalina对象
Catalina类实例化Server在这里读取命令行参数为start,然后启动
// 在这里读取命令行参数为start,然后启动。
daemon.setAwait(true);
daemon.load(args);
daemon.start();
这里的daemon实际上是一个Bootstrap的实例,由main()方法创建
private static Bootstrap daemon = null;
BootStrap中main方法这句代码启动了一个Server实例
daemon.load(args); //这里的daemon实际上是一个Bootstrap的实例
追进去BootStrap中的load方法看看,BootStrap中的load方法调用了Catalina里面的load方法
BootStrap的load方法:
private void load(String[] arguments)
throws Exception {
//catalinaDaemon是一个Catalina实例
// Call the load() method
String methodName = "load";
Object param[];
Class> paramTypes[];
if (arguments==null || arguments.length==0) {
paramTypes = null;
param = null;
} else {
paramTypes = new Class[1];
paramTypes[0] = arguments.getClass();
param = new Object[1];
param[0] = arguments;
}
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled())
log.debug("Calling startup class " + method);
//通过反射调用Catalina类的load方法
method.invoke(catalinaDaemon, param);
}
再追进去,Catalina类里面的load方法
public void load() {
long t1 = System.nanoTime();
initDirs();
// Before digester - it may be needed
initNaming();
// Create and execute our Digester
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
try {
//这里追进去源码看,其实是找到配置文件server.xml
file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail", file), e);
}
}
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream(getConfigFile());
inputSource = new InputSource
(getClass().getClassLoader()
.getResource(getConfigFile()).toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail",
getConfigFile()), e);
}
}
}
// This should be included in catalina.jar
// Alternative: don't bother with xml, just create it manually.
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream("server-embed.xml");
inputSource = new InputSource
(getClass().getClassLoader()
.getResource("server-embed.xml").toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail",
"server-embed.xml"), e);
}
}
}
if (inputStream == null || inputSource == null) {
if (file == null) {
log.warn(sm.getString("catalina.configFail",
getConfigFile() + "] or [server-embed.xml]"));
} else {
log.warn(sm.getString("catalina.configFail",
file.getAbsolutePath()));
if (file.exists() && !file.canRead()) {
log.warn("Permissions incorrect, read permission is not allowed on the file.");
}
}
return;
}
try {
inputSource.setByteStream(inputStream);
//digster库解析xml是采用压栈入栈形式的
//把Catalina实例压栈,这时候Catalina实例在栈底
digester.push(this);
//digster实例解析server.xml文件,
//这里之后Catalina的私有变量server会引用一个已经被解析的Server对象
digester.parse(inputSource);
} catch (SAXParseException spe) {
log.warn("Catalina.start using " + getConfigFile() + ": " +
spe.getMessage());
return;
} catch (Exception e) {
log.warn("Catalina.start using " + getConfigFile() + ": " , e);
return;
}
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// Ignore
}
}
}
//设置这个Server实例的一些属性
getServer().setCatalina(this);
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinabase(Bootstrap.getCatalinabaseFile());
// Stream redirection
initStreams();
// Start the new server
try {
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new java.lang.Error(e);
} else {
log.error("Catalina.start", e);
}
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
}
}
Catalina类中的私有成员变量server
在digester.parse(inputSource)解析之后,会赋值一个StanderServer实例给server,并且在StandardServer中注册了一个StandardService
StanderServer继承LifecycleMBeanbase
LifecycleMBeanbase继承LifecycleMBeanbase
LifecycleMBeanbase继承Lifecyclebase
在接下来这句代码中,
getServer().init();
//实际上StanderServer是调用Lifecyclebase的init()方法,这个方法会触发一个初始化事件,用于初始化其它容器
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
setStateInternal(LifecycleState.INITIALIZING, null, false);
try {
initInternal();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(
sm.getString("lifecyclebase.initFail",toString()), t);
}
setStateInternal(LifecycleState.INITIALIZED, null, false);
}
Context创建与启动
触发一次start事件
到这里之后Catalina类中的load()方法已经走完,server实例也初始化完毕,回到Bootstrap的main方法的代码中
daemon.setAwait(true); daemon.load(args);//这时候走完了这里 daemon.start();
首先由bootStrap中的main方法调用Catalina类里面的start()方法。
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
log.fatal("Cannot start server. Server instance is not configured.");
return;
}
long t1 = System.nanoTime();
// Start the new server
try {
//这里启动一个server
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
}
// Register shutdown hook
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
// If JULI is being used, disable JULI's shutdown hook since
// shutdown hooks run in parallel and log messages may be lost
// if JULI's hook completes before the CatalinaShutdownHook()
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
false);
}
}
if (await) {
await();
stop();
}
}
接着在方法中这句代码,会调用StandardServer里的start()方法
getServer().start();//调用StandardServer里的start()方法
注意,这里调用StandardServer里的start()方法继承自lifecyclebase
public final synchronized void start() throws LifecycleException {
if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) {
if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecyclebase.alreadyStarted", toString()), e);
} else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecyclebase.alreadyStarted", toString()));
}
return;
}
if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}
try {
setStateInternal(LifecycleState.STARTING_PREP, null, false);
startInternal();
if (state.equals(LifecycleState.FAILED)) {
// This is a 'controlled' failure. The component put itself into the
// FAILED state so call stop() to complete the clean-up.
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
invalidTransition(Lifecycle.AFTER_START_EVENT);
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
} catch (Throwable t) {
// This is an 'uncontrolled' failure so put the component into the
// FAILED state and throw an exception.
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(sm.getString("lifecyclebase.startFail", toString()), t);
}
}
上面最重要的是这两句代码
setStateInternal(LifecycleState.STARTING_PREP, null, false);//设置生命周期的状态
startInternal();
追进去startInternal()方法(StandardServer里面的startInternal()方法)
@Override
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
注意:StandardServer和StandService类很容易混淆,请看清楚
Server遍历自身的services数组中的service并启动,这里我们追进去StandardService的start()方法。(这里其实和StandardServer一样,都是继承自lifecycle的start()方法)
在StandardService的start()方法中,又会调用StandardService的startInternal()方法
protected void startInternal() throws LifecycleException {
if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
setState(LifecycleState.STARTING);
// Start our defined Container first
//这里很重要,这个方法会启动Tomcat最顶层的容器engine
if (engine != null) {
synchronized (engine) {
engine.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
mapperListener.start();
// Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
} catch (Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}
追进去engine的start方法看看,其实engine的start方法继承自lifecyclebase,上面已经给出了代码,lifecyclebase又会调用engine的startInternal方法(继承自Containerbase)
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any
logger = null;
getLogger();
Cluster cluster = getClusterInternal();
if (cluster instanceof Lifecycle) {
((Lifecycle) cluster).start();
}
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
// Start our child containers, if any
Container children[] = findChildren();
List> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
MultiThrowable multiThrowable = null;
for (Future result : results) {
try {
result.get();
} catch (Throwable e) {
log.error(sm.getString("containerbase.threadedStartFailed"), e);
if (multiThrowable == null) {
multiThrowable = new MultiThrowable();
}
multiThrowable.add(e);
}
}
if (multiThrowable != null) {
throw new LifecycleException(sm.getString("containerbase.threadedStartFailed"),
multiThrowable.getThrowable());
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
//关键代码
setState(LifecycleState.STARTING);
// Start our thread
threadStart();
}
engine的startInternal方法中,setState(LifecycleState.STARTING)这句代码最为关键。追进去看看
protected synchronized void setState(LifecycleState state)
throws LifecycleException {
setStateInternal(state, null, true);
}
再追进去setStateInternal(state, null, true);
private synchronized void setStateInternal(LifecycleState state,
Object data, boolean check) throws LifecycleException {
if (log.isDebugEnabled()) {
log.debug(sm.getString("lifecyclebase.setState", this, state));
}
if (check) {
// Must have been triggered by one of the abstract methods (assume
// code in this class is correct)
// null is never a valid state
if (state == null) {
invalidTransition("null");
// Unreachable code - here to stop eclipse complaining about
// a possible NPE further down the method
return;
}
// Any method can transition to failed
// startInternal() permits STARTING_PREP to STARTING
// stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
// STOPPING
if (!(state == LifecycleState.FAILED ||
(this.state == LifecycleState.STARTING_PREP &&
state == LifecycleState.STARTING) ||
(this.state == LifecycleState.STOPPING_PREP &&
state == LifecycleState.STOPPING) ||
(this.state == LifecycleState.FAILED &&
state == LifecycleState.STOPPING))) {
// No other transition permitted
invalidTransition(state.name());
}
}
this.state = state;
//这里最关键,会触发一个“start”的生命周期事件
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
fireLifecycleEvent(lifecycleEvent, data);
}
}
这里最关键,会触发一个“start”的生命周期事件
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
fireLifecycleEvent(lifecycleEvent, data);
}
}
好,到这里tomcat已经触发了一次start的生命事件,Host是context的父容器,而且host注册了一个监听器,该监听器监听到start事件后触发Context的创建和启动。这里小弟画了一个流程图,如果上面觉得有些乱可以跟着流程图追一追源码,其实也能看到每个组件都会通过LifeCyclebase来负责启动。
下面我们来看看这个监听器。
监听器启动Context实例因为监听器是注册再Host容器里的,所以我们先来看看Catalina是怎样配置和创建Host类的
//创建host对象
digester.addObjectCreate(prefix + "Host",
"org.apache.catalina.core.StandardHost", //创建host对象的配置
"className");
digester.addSetProperties(prefix + "Host");
digester.addRule(prefix + "Host",
new CopyParentClassLoaderRule()); //会将host的parentClassloader设置为engine的,engine被设置为sharedloader
digester.addRule(prefix + "Host", //为host设置配置的监听
new LifecycleListenerRule
("org.apache.catalina.startup.HostConfig", //这个算是比较重要的吧,在里面会具体的创建context啥的
"hostConfigClass"));
digester.addSetNext(prefix + "Host",
"addChild",
"org.apache.catalina.Container"); // 在engine上面调用addChild方法,用于添加当前的host到engine上面去
从上面就看出来了,在创建Host对象实例的时候,也会创建一个HostConfig并被这个Host实例所引用
而在HostConfig是一个监听器,也就是说,当发生“某个事件”的时候,他会做出“相应的反应”。HostConfig的这个lifecycleEvent方法,就是对具体的事件做出反应的方法,该方法传入一个事件类型,并根据事件类型执行相应的业务逻辑。
public void lifecycleEvent(LifecycleEvent event) {
// Identify the host we are associated with
try {
host = (Host) event.getLifecycle();
if (host instanceof StandardHost) {
setCopyXML(((StandardHost) host).isCopyXML());
setDeployXML(((StandardHost) host).isDeployXML());
setUnpackWARs(((StandardHost) host).isUnpackWARs());
setContextClass(((StandardHost) host).getContextClass());
}
} catch (ClassCastException e) {
log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
return;
}
//这里根据我们前面的一大堆分析,这里会触发一个“start”事件
// Process the event that has occurred
if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
check();
} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
beforeStart();
} else if (event.getType().equals(Lifecycle.START_EVENT)) {
//“start”事件会触发HostConfig的start()方法
start();
} else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
stop();
}
}
接下来我们追进HostConfig的start()方法
public void start() {
if (log.isDebugEnabled())
log.debug(sm.getString("hostConfig.start"));
try {
ObjectName hostON = host.getObjectName();
oname = new ObjectName
(hostON.getDomain() + ":type=Deployer,host=" + host.getName());
Registry.getRegistry(null, null).registerComponent
(this, oname, this.getClass().getName());
} catch (Exception e) {
log.error(sm.getString("hostConfig.jmx.register", oname), e);
}
if (!host.getAppbaseFile().isDirectory()) {
log.error(sm.getString("hostConfig.appbase", host.getName(),
host.getAppbaseFile().getPath()));
host.setDeployOnStartup(false);
host.setAutoDeploy(false);
}
//这里是重要代码,我们继续追进去
if (host.getDeployOnStartup())
deployApps();
}
再追进去这个deployApps()方法
'''
这里要解释一下,这个函数会找到Tomcat目录下wepapp文件夹,并把每一个应用进行部署,即每个应用对应一个Context实例
'''
protected void deployApps() {
File appbase = host.getAppbaseFile();
File configbase = host.getConfigbaseFile();
String[] filteredAppPaths = filterAppPaths(appbase.list());
// Deploy XML descriptors from configbase
deployDescriptors(configbase, configbase.list());
// Deploy WARs
//如果是war包的应用,走这个分支
deployWARs(appbase, filteredAppPaths);
// Deploy expanded folders
//如果是文件夹类型的应用,走这个分析
deployDirectories(appbase, filteredAppPaths);
}
我们追一下文件夹类型的,也就是这个方法deployDirectories(appbase, filteredAppPaths);
protected void deployDirectories(File appbase, String[] files) {
if (files == null)
return;
//这里获取一个host的执行器,会跟context的启动和关闭有关
ExecutorService es = host.getStartStopExecutor();
List> results = new ArrayList<>();
//遍历目录,每个逐个部署
for (int i = 0; i < files.length; i++) {
if (files[i].equalsIgnoreCase("meta-INF"))
continue;
if (files[i].equalsIgnoreCase("WEB-INF"))
continue;
File dir = new File(appbase, files[i]);
if (dir.isDirectory()) {
ContextName cn = new ContextName(files[i], false);
if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
continue;
//重要代码,这里执行部署
results.add(es.submit(new DeployDirectory(this, cn, dir)));
}
}
for (Future> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString(
"hostConfig.deployDir.threaded.error"), e);
}
}
}
这行代码向执行器提交了一个任务,实际上就是创建应用对应的context对象
注意这个方法名字deployDirectory,和前面的deployDirectories是单数和复数的区别,不要混淆了
protected void deployDirectory(ContextName cn, File dir) {
long startTime = 0;
// Deploy the application in this directory
if( log.isInfoEnabled() ) {
startTime = System.currentTimeMillis();
log.info(sm.getString("hostConfig.deployDir",
dir.getAbsolutePath()));
}
Context context = null;
File xml = new File(dir, Constants.ApplicationContextXml);
File xmlCopy =
new File(host.getConfigbaseFile(), cn.getbaseName() + ".xml");
DeployedApplication deployedApp;
boolean copyThisXml = isCopyXML();
boolean deployThisXML = isDeployThisXML(dir, cn);
try {
if (deployThisXML && xml.exists()) {
synchronized (digesterLock) {
try {
//这句话解析了xml文件之后,context这个变量已经引用了一个Context的实例
//也就是说这时候Context已经创建好了
context = (Context) digester.parse(xml);
} catch (Exception e) {
log.error(sm.getString(
"hostConfig.deployDescriptor.error",
xml), e);
context = new FailedContext();
} finally {
digester.reset();
if (context == null) {
context = new FailedContext();
}
}
}
if (copyThisXml == false && context instanceof StandardContext) {
// Host is using default value. Context may override it.
copyThisXml = ((StandardContext) context).getCopyXML();
}
if (copyThisXml) {
Files.copy(xml.toPath(), xmlCopy.toPath());
context.setConfigFile(xmlCopy.toURI().toURL());
} else {
context.setConfigFile(xml.toURI().toURL());
}
} else if (!deployThisXML && xml.exists()) {
// Block deployment as meta-INF/context.xml may contain security
// configuration necessary for a secure deployment.
log.error(sm.getString("hostConfig.deployDescriptor.blocked",
cn.getPath(), xml, xmlCopy));
context = new FailedContext();
} else {
context = (Context) Class.forName(contextClass).getConstructor().newInstance();
}
//这里为这个context实例开始设置一些属性
Class> clazz = Class.forName(host.getConfigClass());
LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance();
context.addLifecycleListener(listener);
context.setName(cn.getName());
context.setPath(cn.getPath());
context.setWebappVersion(cn.getVersion());
context.setDocbase(cn.getbaseName());
host.addChild(context);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("hostConfig.deployDir.error",
dir.getAbsolutePath()), t);
} finally {
创建DeployedApplication对象,表设一个部署的应用
deployedApp = new DeployedApplication(cn.getName(),
xml.exists() && deployThisXML && copyThisXml);
// Fake re-deploy resource to detect if a WAR is added at a later
// point
deployedApp.redeployResources.put(dir.getAbsolutePath() + ".war",
Long.valueOf(0));
deployedApp.redeployResources.put(dir.getAbsolutePath(),
Long.valueOf(dir.lastModified()));
if (deployThisXML && xml.exists()) {//如果有context的配置文件,用context的配置
if (copyThisXml) {
deployedApp.redeployResources.put(
xmlCopy.getAbsolutePath(),
Long.valueOf(xmlCopy.lastModified()));
} else {
deployedApp.redeployResources.put(
xml.getAbsolutePath(),
Long.valueOf(xml.lastModified()));
// Fake re-deploy resource to detect if a context.xml file is
// added at a later point
deployedApp.redeployResources.put(
xmlCopy.getAbsolutePath(),
Long.valueOf(0));
}
} else {
// Fake re-deploy resource to detect if a context.xml file is
// added at a later point
deployedApp.redeployResources.put(
xmlCopy.getAbsolutePath(),
Long.valueOf(0));
if (!xml.exists()) {
deployedApp.redeployResources.put(
xml.getAbsolutePath(),
Long.valueOf(0));
}
}
addWatchedResources(deployedApp, dir.getAbsolutePath(), context);
// Add the global redeploy resources (which are never deleted) at
// the end so they don't interfere with the deletion process
addGlobalRedeployResources(deployedApp); //添加全局配置
}
deployed.put(cn.getName(), deployedApp);//表示该应用已经部属
if( log.isInfoEnabled() ) {
log.info(sm.getString("hostConfig.deployDir.finished",
dir.getAbsolutePath(), Long.valueOf(System.currentTimeMillis() - startTime)));
}
}
这时候Context已经创建完成啦,同理,其它组件中会注册有监听器,在触发lifecycle事件之后,会触发相应的启动方法。在组件都启动玩之后,Catalina类中的getServer().start()返回,接着执行接下来的代码。
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
log.fatal("Cannot start server. Server instance is not configured.");
return;
}
long t1 = System.nanoTime();
// Start the new server
try {
getServer().start();//组件启动完后从这里返回
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
}
// Register shutdown hook
//注册关闭服务的钩子
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
// If JULI is being used, disable JULI's shutdown hook since
// shutdown hooks run in parallel and log messages may be lost
// if JULI's hook completes before the CatalinaShutdownHook()
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
false);
}
}
if (await) {
//调用await函数接收连接
//Catalina的await()方法会调用server的await()方法
await();
stop();
}
}
public void await() {
// Negative values - don't wait on port - tomcat is embedded or we just don't like ports
if( port == -2 ) {
// undocumented yet - for embedding apps that are around, alive.
return;
}
if( port==-1 ) {
try {
awaitThread = Thread.currentThread();
while(!stopAwait) {
try {
Thread.sleep( 10000 );
} catch( InterruptedException ex ) {
// continue and check the flag
}
}
} finally {
awaitThread = null;
}
return;
}
// Set up a server socket to wait on
try {
awaitSocket = new ServerSocket(port, 1,
InetAddress.getByName(address));
} catch (IOException e) {
log.error("StandardServer.await: create[" + address
+ ":" + port
+ "]: ", e);
return;
}
try {
awaitThread = Thread.currentThread();
// Loop waiting for a connection and a valid command
while (!stopAwait) {
ServerSocket serverSocket = awaitSocket;
if (serverSocket == null) {
break;
}
// Wait for the next connection
Socket socket = null;
StringBuilder command = new StringBuilder();
try {
InputStream stream;
long acceptStartTime = System.currentTimeMillis();
try {
socket = serverSocket.accept();
socket.setSoTimeout(10 * 1000); // Ten seconds
stream = socket.getInputStream();
} catch (SocketTimeoutException ste) {
// This should never happen but bug 56684 suggests that
// it does.
log.warn(sm.getString("standardServer.accept.timeout",
Long.valueOf(System.currentTimeMillis() - acceptStartTime)), ste);
continue;
} catch (AccessControlException ace) {
log.warn("StandardServer.accept security exception: "
+ ace.getMessage(), ace);
continue;
} catch (IOException e) {
if (stopAwait) {
// Wait was aborted with socket.close()
break;
}
log.error("StandardServer.await: accept: ", e);
break;
}
// Read a set of characters from the socket
int expected = 1024; // Cut off to avoid DoS attack
while (expected < shutdown.length()) {
if (random == null)
random = new Random();
expected += (random.nextInt() % 1024);
}
while (expected > 0) {
int ch = -1;
try {
ch = stream.read();
} catch (IOException e) {
log.warn("StandardServer.await: read: ", e);
ch = -1;
}
if (ch < 32) // Control character or EOF terminates loop
break;
command.append((char) ch);
expected--;
}
} finally {
// Close the socket now that we are done with it
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
// Ignore
}
}
// Match against our command string
boolean match = command.toString().equals(shutdown);
if (match) {
log.info(sm.getString("standardServer.shutdownViaPort"));
break;
} else
log.warn("StandardServer.await: Invalid command '"
+ command.toString() + "' received");
}
} finally {
ServerSocket serverSocket = awaitSocket;
awaitThread = null;
awaitSocket = null;
// Close the server socket and return
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// Ignore
}
}
}
}
这时候Tomcat已经启动完毕了。await函数无非就是调用socket接收请求,如果收到的请求是shutdonwn命令,就回跳出while循环,回到BootStrap的main函数中,接着main函数继续执行,程序结束。
总结其实总来的说,context对象的创建就是HostConfig监听到一个“Start”事件时创建的。由于本人技术有限,只是简单的追了追源码,如果有不对的地方还希望大家批评指正,谢谢。



