在上一章查看tomcat启动文件都干点啥---catalina.bat,说了在catalina.bat中都走了什么流程,最重要的是,我们得出了如下这段命令:

_EXECJAVA=start "Tomcat" "E:\Program Files\Java\jdk1.7.0_40\bin\java"JAVA_OPTS= -Djava.util.logging.config.file="F:\apache-tomcat-7.0.8\conf\logging.properties"-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager

CATALINA_OPTS=DEBUG_OPTS=-Djava.endorsed.dirs="F:\apache-tomcat-7.0.8\endorsed"-classpath"F:\apache-tomcat-7.0.8\bin\bootstrap.jar;F:\apache-tomcat-7.0.8\bin\tomcat-juli.jar"-Dcatalina.base="F:\apache-tomcat-7.0.8"-Dcatalina.home="F:\apache-tomcat-7.0.8"-Djava.io.tmpdir="F:\apache-tomcat-7.0.8\temp"MAINCLASS=org.apache.catalina.startup.Bootstrap

CMD_LINE_ARGS= ACTION=start

其中很重要的一个属性是:MAINCLASS=org.apache.catalina.startup.Bootstrap,Bootstrap在bootstrap.jar中,我们看一下Bootstrap的类图:

从每个变量和方法的名字的字面上也能大概看出来变量或者方法的作用。

很显然,程序走到Bootstrap的时候首先调用main方法,main方法是通过脚本启动tomcat的入口,我们看一下main方法中实现的内容:

if (daemon == null) {//Don't set daemon until init() has completed

Bootstrap bootstrap = newBootstrap();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{

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")) {

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);

}

View Code

可以看出main方法主要实现了两个功能:

(1)初始化一个守护进程变量。

(2)加载参数,解析命令,并执行。

下面是初始化守护进程的执行过程:

if (daemon == null) {//Don't set daemon until init() has completed

Bootstrap bootstrap = newBootstrap();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);

}

可以看到在bootstrap.init()方法中对bootstrap变量进行初始化,然后将结果返回给daemon。下面看一下init方法中的实现:

public voidinit()throwsException

{//Set Catalina path

setCatalinaHome();

setCatalinaBase();

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");

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);

catalinaDaemon=startupInstance;

}

View Code

init方法中对classLoader进行了初始化,设置了引用的catalinaDaemon变量。

对于如何定义catalinaDaemon变量是应用反射机制:

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);

catalinaDaemon= startupInstance;

下面着重说一下关于classLoader。

在Bootstrap类中,最开始的地方,有三个ClassLoader的定义,内容如下:

protected ClassLoader commonLoader = null;protected ClassLoader catalinaLoader = null;protected ClassLoader sharedLoader = null;

先不说这三个classLoader之间的关系,先看一下Bootstrap上的注释也有关于classLoader的说明:

* Bootstrap loader for Catalina. This application constructs a classloader* foruse in loading the Catalina internal classes (by accumulating all of the* JAR files found in the "server" directory under "catalina.home"), and* starts the regular execution of the container. The purpose of this

*roundabout approach is to keep the Catalina internal classes (and any*other classes they depend on, such as an XML parser) out of the system* class path and therefore not visible to application level classes.

翻译过来就是说:Bootstrap第一个功能是引导Catalina,Bootstrap构造一个class loader来加载Catalina的内部类(所有在catalina.home中的jar文件),第二个功能是启动container。实现catalina的内部类和系统的class path以及应用程序中的class要区分开不能相互访问的目的。

//Set Catalina path

setCatalinaHome();

setCatalinaBase();

initClassLoaders();

Thread.currentThread().setContextClassLoader(catalinaLoader);

SecurityClassLoad.securityClassLoad(catalinaLoader);

设置当前的线程的class loader为catalinaLoader。使用catalinaLoader加载catalina类,实现反射,定义catalina的反射。然后重点看一下 initClassLoaders()方法的实现:

try{

commonLoader= createClassLoader("common", null);if( commonLoader == null) {//no config file, default to this loader - we might be in a 'single' env.

commonLoader=this.getClass().getClassLoader();

}

catalinaLoader= createClassLoader("server", commonLoader);

sharedLoader= createClassLoader("shared", commonLoader);

}catch(Throwable t) {

handleThrowable(t);

log.error("Class loader creation threw exception", t);

System.exit(1);

}

在看一下createClassLoader方法的内容:

privateClassLoader createClassLoader(String name, ClassLoader parent)throwsException {

String value= CatalinaProperties.getProperty(name + ".loader");if ((value == null) || (value.equals("")))returnparent;

value=replace(value);

List repositories = new ArrayList();

StringTokenizer tokenizer= new StringTokenizer(value, ",");while(tokenizer.hasMoreElements()) {

String repository=tokenizer.nextToken().trim();if (repository.length() == 0) {continue;

}//Check for a JAR URL repository

try{

@SuppressWarnings("unused")

URL url= newURL(repository);

repositories.add(newRepository(repository, RepositoryType.URL));continue;

}catch(MalformedURLException e) {//Ignore

}//Local repository

if (repository.endsWith("*.jar")) {

repository=repository.substring

(0, repository.length() - "*.jar".length());

repositories.add(newRepository(repository, RepositoryType.GLOB));

}else if (repository.endsWith(".jar")) {

repositories.add(newRepository(repository, RepositoryType.JAR));

}else{

repositories.add(newRepository(repository, RepositoryType.DIR));

}

}

ClassLoader classLoader=ClassLoaderFactory.createClassLoader

(repositories, parent);//Retrieving MBean server

MBeanServer mBeanServer = null;if (MBeanServerFactory.findMBeanServer(null).size() > 0) {

mBeanServer= MBeanServerFactory.findMBeanServer(null).get(0);

}else{

mBeanServer=ManagementFactory.getPlatformMBeanServer();

}//Register the server classloader

ObjectName objectName =

new ObjectName("Catalina:type=ServerClassLoader,name=" +name);

mBeanServer.registerMBean(classLoader, objectName);returnclassLoader;

}

View Code

在该方法中引入了CatalinaProperties类,下面看一下CatalinaProperties的内容:

这个类主要是加载catalina.properties配置文件,然后将其中的内容保存到当前环境中,首先查看$CATALINA_BASE/conf/catalina.propertie是否存在,如果不存在的话去读取Bootstrap.jar中的catalina.propertie的文件,如果没有在$CATALINA_BASE/conf/中配置catalina.propertie文件,那么catalina.propertie内容如下所示(tomcat版本大于5.x):

# Licensed to the Apache Software Foundation (ASF) under one or more

# contributor license agreements. See the NOTICE file distributed with

#this work foradditional information regarding copyright ownership.

# The ASF licensesthis file to You under the Apache License, Version 2.0# (the"License"); you may not use thisfile 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 Licenseforthe specific language governing permissions and

# limitations under the License.

#

# List of comma-separated packages that start with or equal thisstring

# will cause a security exception to be thrown when

# passed to checkPackageAccess unless the

# corresponding RuntimePermission ("accessClassInPackage."+package) has

# been granted.package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.

#

# List of comma-separated packages that start with or equal thisstring

# will cause a security exception to be thrown when

# passed to checkPackageDefinition unless the

# corresponding RuntimePermission ("defineClassInPackage."+package) has

# been granted.

#

# bydefault, no packages are restricted fordefinition, and none of

# theclassloaders supplied with the JDK call checkPackageDefinition.

#package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.

#

#

# List of comma-separated paths defining the contents of the "common"# classloader. Prefixes should be used to define what is the repository type.

# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.

# If left as blank,the JVM system loader will be used as Catalina's "common"

# loader.

# Examples:

#"foo": Add this folder as a classrepository

#"foo/*.jar": Add all the JARs of the specified folder as class# repositories

#"foo/bar.jar": Add bar.jar as a classrepository

common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar

#

# List of comma-separated paths defining the contents of the "server"

# classloader. Prefixes should be used to define what is the repository type.

# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.

# If left as blank, the "common" loader will be used as Catalina's "server"

# loader.

# Examples:

# "foo": Add this folder as a class repository

# "foo/*.jar": Add all the JARs of the specified folder as class

# repositories

# "foo/bar.jar": Add bar.jar as a class repository

server.loader=

#

# List of comma-separated paths defining the contents of the "shared"

# classloader. Prefixes should be used to define what is the repository type.

# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,

# the "common" loader will be used as Catalina's "shared" loader.

# Examples:

# "foo": Add this folder as a class repository

# "foo/*.jar": Add all the JARs of the specified folder as class

# repositories

# "foo/bar.jar": Add bar.jar as a class repository

# Please note that for single jars, e.g. bar.jar, you need the URL form

# starting with file:.

shared.loader=

#

# String cache configuration.

tomcat.util.buf.StringCache.byte.enabled=true

#tomcat.util.buf.StringCache.char.enabled=true

#tomcat.util.buf.StringCache.trainThreshold=500000

#tomcat.util.buf.StringCache.cacheSize=5000

在联系在Bootstrap.java中的这段代码:

String value = CatalinaProperties.getProperty(name + ".loader");if ((value == null) || (value.equals("")))return parent;

有没有感觉很奇怪,shared.loader,server.loader这两个配置都为空,所以通过initClassLoaders方法可以得出结论,catalinaLoader,sharedLoader均指向commonLoader的引用,所以在apache网站上的classLoader树如下展示:

但是拿两个classLoader为什么会定义呢,那就要看一下在tomcat5.x时代时候的catalina.propertie内容:

server.loader=${catalina.home}/server/classes,${catalina.home}/server/lib/*.jar

shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar

catalinaLoader,sharedLoader这可能就是历史遗留的问题了。关于这两个classLoader的内容请在tomcat5.x找答案。

OK,下面我们只需要关注commonLoader变量了,在catalina.properties配置文件中可以得出

common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar

下面相信看一下tomcat如何处理commonLoader:

当createClassLoader的参数为common,null的时候,

String value = CatalinaProperties.getProperty(name + ".loader");

此时的value为配置文件中的值(在我的调试环境中,下同):

${catalina.home}/lib,${catalina.home}/lib/*.jar

这个变量可能是不能解析的,需要将${catalina.home}替换为系统的据对路径,通过replace方法替换,可以看一下replace的定义:

protectedString replace(String str) {//Implementation is copied from ClassLoaderLogManager.replace(),//but added special processing for catalina.home and catalina.base.

String result =str;int pos_start = str.indexOf("${");if (pos_start >= 0) {

StringBuilder builder= newStringBuilder();int pos_end = -1;while (pos_start >= 0) {

builder.append(str, pos_end+ 1, pos_start);

pos_end= str.indexOf('}', pos_start + 2);if (pos_end < 0) {

pos_end= pos_start - 1;break;

}

String propName= str.substring(pos_start + 2, pos_end);

String replacement;if (propName.length() == 0) {

replacement= null;

}else if(Globals.CATALINA_HOME_PROP.equals(propName)) {

replacement=getCatalinaHome();

}else if(Globals.CATALINA_BASE_PROP.equals(propName)) {

replacement=getCatalinaBase();

}else{

replacement=System.getProperty(propName);

}if (replacement != null) {

builder.append(replacement);

}else{

builder.append(str, pos_start, pos_end+ 1);

}

pos_start= str.indexOf("${", pos_end + 1);

}

builder.append(str, pos_end+ 1, str.length());

result=builder.toString();

}returnresult;

}

View Code

通过replace返回的结果为:

value=F:\ITSM_V3.1\tomcatSource/lib,F:\ITSM_V3.1\tomcatSource/lib/*.jar

然后顺序执行,很容易得出结论,在执行

ClassLoader classLoader =ClassLoaderFactory.createClassLoader(repositories, parent);

时候的repositories的值为:

调用ClassLoaderFactory类中的静态方法createClassLoader,其定义如下:

public static ClassLoader createClassLoader(Listrepositories,finalClassLoader parent)throwsException {if(log.isDebugEnabled())

log.debug("Creating new class loader");//Construct the "class path" for this class loader

Set set = new LinkedHashSet();if (repositories != null) {for(Repository repository : repositories) {if (repository.getType() ==RepositoryType.URL) {

URL url= newURL(repository.getLocation());if(log.isDebugEnabled())

log.debug(" Including URL " +url);

set.add(url);

}else if (repository.getType() ==RepositoryType.DIR) {

File directory= newFile(repository.getLocation());

directory=directory.getCanonicalFile();if (!validateFile(directory, RepositoryType.DIR)) {continue;

}

URL url=directory.toURI().toURL();if(log.isDebugEnabled())

log.debug(" Including directory " +url);

set.add(url);

}else if (repository.getType() ==RepositoryType.JAR) {

File file=newFile(repository.getLocation());

file=file.getCanonicalFile();if (!validateFile(file, RepositoryType.JAR)) {continue;

}

URL url=file.toURI().toURL();if(log.isDebugEnabled())

log.debug(" Including jar file " +url);

set.add(url);

}else if (repository.getType() ==RepositoryType.GLOB) {

File directory=newFile(repository.getLocation());

directory=directory.getCanonicalFile();if (!validateFile(directory, RepositoryType.GLOB)) {continue;

}if(log.isDebugEnabled())

log.debug(" Including directory glob "

+directory.getAbsolutePath());

String filenames[]=directory.list();for (int j = 0; j < filenames.length; j++) {

String filename=filenames[j].toLowerCase(Locale.ENGLISH);if (!filename.endsWith(".jar"))continue;

File file= newFile(directory, filenames[j]);

file=file.getCanonicalFile();if (!validateFile(file, RepositoryType.JAR)) {continue;

}if(log.isDebugEnabled())

log.debug(" Including glob jar file "

+file.getAbsolutePath());

URL url=file.toURI().toURL();

set.add(url);

}

}

}

}//Construct the class loader itself

final URL[] array = set.toArray(newURL[set.size()]);if(log.isDebugEnabled())for (int i = 0; i < array.length; i++) {

log.debug(" location " + i + " is " +array[i]);

}returnAccessController.doPrivileged(new PrivilegedAction() {

@OverridepublicStandardClassLoader run() {if (parent == null)return newStandardClassLoader(array);else

return newStandardClassLoader(array, parent);

}

});

}

View Code

最后返回的 return new StandardClassLoader(array);其中array是一个URL类型的数组,看结果的时候要对照前面的内容file:/F:/ITSM_V3.1/tomcatSource/lib/, file:/F:/ITSM_V3.1/tomcatSource/lib/annotations-api.jar.......(file:/F:/ITSM_V3.1/tomcatSource/lib/下的所有jar文件)。

然后将classLoader注册到MBeanServer中,然后返回classLoader。然后用返回的classLoader加载org.apache.catalina.startup.Catalina,然后进行反射。调用对应的方法。

下面说一下main方法的第二个作用,加载参数,解析命令,并执行

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")) {

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.");

}

其中load方法是将命令行定义的参数传递给通过反射调用的catalinaDaemon.load方法。然后执行的方法也就是在实现的时候调用catalinaDaemon中对应的方法,例如:

/*** Stop the Catalina Daemon.*/

public voidstop()throwsException {

Method method= catalinaDaemon.getClass().getMethod("stop", (Class [] ) null);

method.invoke(catalinaDaemon, (Object [] )null);

}

在此文中我们得出在(tomcat7.0版本中):

(1)Bootstrap中如何通过创建的commonLoader=catalinaLoader=sharedLoader来加载类。

(2)在Bootstrap中使用反射机智来加载来调用catalinaDaemon中的方法。

(3)如何获取catalina.properties配置文件。

如果有疑问或者不对的地方,请指出。谢谢。

bootstrap java_查看tomcat启动文件都干点啥---Bootstrap.java相关推荐

  1. 查看tomcat启动文件都干点啥---server对象

    在上一章查看tomcat启动文件都干点啥---Catalina.java中说道了构造Server,,这次尝试着说一下Tomcat中Server的内容,首先看一下org.apache.catalina. ...

  2. tomact错误日志是那个_如何查看tomcat启动异常日志详情

    我的电脑同时使用两个jdk版本,默认1.7,eclipse使用的是1.8,,由于项目启动时有加载类需要jdk1.8的包,1.7不支持.所以导致项目在eclipse直接能够跑,而在外面的tomcat跑是 ...

  3. Linux下查看Tomcat进程查看Tomcat启动日志

    在Linux系统下,重启Tomcat使用命令的操作! 1.首先,进入Tomcat下的bin目录 cd /usr/local/tomcat/bin 使用Tomcat关闭命令 ./shutdown.sh ...

  4. 查看tomcat启动日志

    前言 查看tomcat启动日志需要注意的是看清楚自己的安装目录,不一定是我下面写的. 1.先切换到:cd /usr/local/tomcat/apache-tomcat-8.5.41/logs/ 2. ...

  5. linux查看tomcat启动内存溢出,关于tomcat乱码以及tomcat jvm 内存溢出问题的解决方案和理论-Fun言...

    一:乱码问题1(前端通过url方式传递中文参数后台收到的是????) 此为Tomcat根目录-conif-server.xml 中 connectionTimeout="20000″ red ...

  6. 动态查看tomcat日志文件

    在服务器中调试程序的时候,动态查看日志信息 切换到tomcat/logs文件夹下 执行 tail -f catalina.out 命令,就可以看到一些调试信息 ctrl + c 就可以结束查看

  7. 怎么让cmd命令行不关闭或查看tomcat启动一闪而过的原因

    场景:在运行tomcat的时候或者其他的bat文件,想保持cmd命令行窗口一直打开,以便查看里面的信息 现在你有一个startup.bat命令行文件,一般情况下正常启动是可以一直显示cmd命令行窗口的 ...

  8. linux查看tomcat启动内存溢出,Linux下 Tomcat内存溢出

    Tomcat本身不能直接在计算机上运行,需要依赖于操作系统和一个Java虚拟机.JAVA程序启动时JVM会分配一个初始内存和最大内存给APP.当APP需要的内存超出内存的最大值时虚拟机就会提示内存溢出 ...

  9. linux查看运行钟的tomcat,linux查看tomcat启动运行日志

    Linux0.11内核--进程调度分析之2.调度 [版权所有,转载请注明出处.出处:http://www.cnblogs.com/joey-hua/p/5596830.html ] 上一篇说到进程调度 ...

最新文章

  1. 3.分支结构与循环结构
  2. 这些Spring中的设计模式,你都知道吗?
  3. springboot启动流程
  4. 高仿真的类-请求url
  5. 鸟瞰 MySQL,唬住面试官!
  6. 仪征技师学院计算机,技师学院2019年下半年江苏省大学英语、大学计算机统考工作圆满结束...
  7. 先河系统为你讲解私有云服务器的优点
  8. Quartus II 12.1安装及破解
  9. CAT8八类网线标准、测试与应用
  10. 联想服务器ts系列介绍,联想服务器ThinkServerTS230.ppt
  11. T440s 黑苹果折腾
  12. 云队友丨张朝阳不再狂妄,搜狐的艰难复苏路
  13. IT是什么行业?就业前景怎么样
  14. 世界杯吉祥物玩偶难产?俄罗斯人紧急求助这个杭州男人
  15. 转载 总结了一下十几年来的经验教训
  16. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part7项目优化与打包
  17. php 数字 字母组合,php随机生成数字字母组合的方法_php技巧
  18. CSS实现div填满剩余高度
  19. ‘数据库基础、MariaDB服务部署、库表基本管理、数据类型’经典案例
  20. Jess学习基础(一)

热门文章

  1. 又爱又恨的 Microsoft Edge!
  2. 在Windows系统利用IP地址登陆Linux服务器
  3. EST | 系统评价污水样品中选定药物、非法药物及其代谢物的稳定性
  4. 青年生命科学论坛报告:扩增子和宏基因组数据分析与可视化流程—刘永鑫(北京210606)...
  5. 高颜值免费在线SCI绘图工具增加上传功能
  6. R语言可视化学习笔记之ggridges包
  7. 你看的每一篇Nature论文,都是这样出炉的!
  8. 亦正亦邪,骨骼惊奇的LGG
  9. 下面属于java的object_在JAVA中,下列哪些是Object类的方法()
  10. 黑金花大理石_黑金花 , 经典就是经典 ! 美 !