Tomcat源码分析(一)--初始化init(Bootstrap启动)
下载tomcat 8.0源码可以到tomcat官网去下载 source code distributions 选择zip,下载完新建一个pom.xml就可以导入到eclipse中了。其实知道Tomcat源码就可以把spring Web项目整个运行流程就可以想明白。
一、Tomcat总体结构
一个Tomcat中只有一个Server,一个Server可以包含多个Service,一个Service只有一个Cotainer,但可以有多个Connectors,
(因为一个服务可以有多个连接,如同时提供http和https连接,也可以提供相同协议不同端口的接口)
Tomcat最顶层的容器就叫Server,代表整个服务器,Server包含一个或多个的Service.
Service包括了Connector和Container.
Tomcat里的Server由org.apache,catalina.startup.Catalina来管理。Catalina类的三个方法start,stop,load分别管理整个服务器的生命周期。
load方法用于根据conf/server.xml文件创建Server并调用Server的init方法进行初始化,
---》 Catalina类的load()方法详细解释在 (Tomcat源码分析(二))
start方法用于启动服务器,stop方法用于停止服务器,start和stop都调用了Server的start和stop方法。load方法内部调用了Server的init方法。
Server的start方法--->所有的Service中的start方法-->调用所有包含Connector和Container的start方法-》启动了服务器
init和stop方法也是一样。
/**
* Await and shutdown.
*/
public void await() {
getServer().await();
}
Catalina的await方法--》Server的await方法 作用是进入一个循环,让主线程不会退出。
二、Tomcat的启动入口
Catalina类主要负责 具体的管理类,而Bootstrap类是启动的入口(main方法)。
Bootstrap类main方法:
/**
* Main method and entry point when starting Tomcat via the provided
* scripts.
*
* @param args Command line arguments to be processed
*/
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 {
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);
}
}
如果args参数为空,默认执行start。
main方法内:
bootstrap.init();
具体的实现init()方法:
/**
* Initialize daemon.
*/
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");
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().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;
}
1、初始化ClassLoader(initClassLoaders)
创建commonLoader、catalinaLoader和sharedLoader;
代码如下:
private void 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); //这里如果获取不到server.loader对应的value值就会返回commonLoader。
sharedLoader = createClassLoader("shared", commonLoader);
} catch (Throwable t) {
handleThrowable(t);
log.error("Class loader creation threw exception", t);
System.exit(1);
}
}
createClassLoader方法
代码如下:
private ClassLoader createClassLoader(String name, ClassLoader parent)
throws Exception {
String value = CatalinaProperties.getProperty(name + ".loader");
if ((value == null) || (value.equals("")))
return parent;
value = replace(value);
List<Repository> repositories = new ArrayList<>();
String[] repositoryPaths = getPaths(value);
for (String repository : repositoryPaths) {
// Check for a JAR URL repository
try {
@SuppressWarnings("unused")
URL url = new URL(repository);
repositories.add(
new Repository(repository, RepositoryType.URL));
continue;
} catch (MalformedURLException e) {
// Ignore
}
// Local repository
if (repository.endsWith("*.jar")) {
repository = repository.substring
(0, repository.length() - "*.jar".length());
repositories.add(
new Repository(repository, RepositoryType.GLOB));
} else if (repository.endsWith(".jar")) {
repositories.add(
new Repository(repository, RepositoryType.JAR));
} else {
repositories.add(
new Repository(repository, RepositoryType.DIR));
}
}
return ClassLoaderFactory.createClassLoader(repositories, parent);
}
ClassLoaderFactory类的ClassLoaderFactory.createClassLoader(repositories, parent);具体实现代码如下:
/**
* Create and return a new class loader, based on the configuration
* defaults and the specified directory paths:
*
* @param repositories List of class directories, jar files, jar directories
* or URLS that should be added to the repositories of
* the class loader.
* @param parent Parent class loader for the new class loader, or
* <code>null</code> for the system class loader.
*
* @exception Exception if an error occurs constructing the class loader
*/
public static ClassLoader createClassLoader(List<Repository> repositories,
final ClassLoader parent)
throws Exception {
if (log.isDebugEnabled())
log.debug("Creating new class loader");
// Construct the "class path" for this class loader
Set<URL> set = new LinkedHashSet<>();
if (repositories != null) {
for (Repository repository : repositories) {
if (repository.getType() == RepositoryType.URL) {
URL url = buildClassLoaderUrl(repository.getLocation());
if (log.isDebugEnabled())
log.debug(" Including URL " + url);
set.add(url);
} else if (repository.getType() == RepositoryType.DIR) {
File directory = new File(repository.getLocation());
directory = directory.getCanonicalFile();
if (!validateFile(directory, RepositoryType.DIR)) {
continue;
}
URL url = buildClassLoaderUrl(directory);
if (log.isDebugEnabled())
log.debug(" Including directory " + url);
set.add(url);
} else if (repository.getType() == RepositoryType.JAR) {
File file=new File(repository.getLocation());
file = file.getCanonicalFile();
if (!validateFile(file, RepositoryType.JAR)) {
continue;
}
URL url = buildClassLoaderUrl(file);
if (log.isDebugEnabled())
log.debug(" Including jar file " + url);
set.add(url);
} else if (repository.getType() == RepositoryType.GLOB) {
File directory=new File(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();
if (filenames == null) {
continue;
}
for (int j = 0; j < filenames.length; j++) {
String filename = filenames[j].toLowerCase(Locale.ENGLISH);
if (!filename.endsWith(".jar"))
continue;
File file = new File(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 = buildClassLoaderUrl(file);
set.add(url);
}
}
}
}
// Construct the class loader itself
final URL[] array = set.toArray(new URL[set.size()]);
if (log.isDebugEnabled())
for (int i = 0; i < array.length; i++) {
log.debug(" location " + i + " is " + array[i]);
}
return AccessController.doPrivileged(
new PrivilegedAction<URLClassLoader>() {
@Override
public URLClassLoader run() {
if (parent == null)
return new URLClassLoader(array);
else
return new URLClassLoader(array, parent);
}
});
}
把从catalina.properties文件中拿到的xx.loader对应的value值,组装成URLClassLoader对象。
具体的new URLClassLoader(array);实现如下:
public URLClassLoader(URL[] urls) {
super();
// this is to make the stack depth consistent with 1.1
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
this.acc = AccessController.getContext();
ucp = new URLClassPath(urls, acc);
}
CatalinaProperties类的getProperty方法获取 loader.
/**
* Return specified property value.
*/
public static String getProperty(String name) {
return properties.getProperty(name);
}
CatalinaProperties类在在类初次被加载的时候调用了loadProperties();
static {
loadProperties();
}
/**
* Load properties.加载配置信息
*/
private static void loadProperties() {
InputStream is = null;
Throwable error = null;
try { //从系统变量中查找
String configUrl = System.getProperty("catalina.config");
if (configUrl != null) {
is = (new URL(configUrl)).openStream();
}
} catch (Throwable t) {
handleThrowable(t);
}
if (is == null) { //从tomcat的conf目录下找到catalina.properties文件加载
try {
File home = new File(Bootstrap.getCatalinaBase());
File conf = new File(home, "conf");
File propsFile = new File(conf, "catalina.properties");
is = new FileInputStream(propsFile);
} catch (Throwable t) {
handleThrowable(t);
}
}
if (is == null) { //从类路径中加载
try {
is = CatalinaProperties.class.getResourceAsStream
("/org/apache/catalina/startup/catalina.properties");
} catch (Throwable t) {
handleThrowable(t);
}
}
if (is != null) { //如果已经找到则加载
try {
properties = new Properties();
properties.load(is);
} catch (Throwable t) {
handleThrowable(t);
error = t;
} finally {
try {
is.close();
} catch (IOException ioe) {
log.warn("Could not close catalina.properties", ioe);
}
}
}
if ((is == null) || (error != null)) {
// Do something
log.warn("Failed to load catalina.properties", error);
// That's fine - we have reasonable defaults.
properties = new Properties();
}
// Register the properties as system properties
//将这些配置变量注册为系统变量
Enumeration<?> enumeration = properties.propertyNames();
while (enumeration.hasMoreElements()) {
String name = (String) enumeration.nextElement();
String value = properties.getProperty(name);
if (value != null) {
System.setProperty(name, value);
}
}
}
System.getProperty("catalina.config"):
System.getProperty 就是从系统的变量中获取值。
序号 | 属性 | 说明 |
1 | java.version | Java 运行时环境版本 |
2 | java.vendor | Java 运行时环境供应商 |
3 | java.vendor.url | Java 供应商的 URL |
4 | java.home | Java 安装目录 |
5 | java.vm.specification.version | Java 虚拟机规范版本 |
6 | java.vm.specification.vendor | Java 虚拟机规范供应商 |
7 | java.vm.specification.name | Java 虚拟机规范名称 |
8 | java.vm.version | Java 虚拟机实现版本 |
9 | java.vm.vendor | Java 虚拟机实现供应商 |
10 | java.vm.name | Java 虚拟机实现名称 |
11 | java.specification.version | Java 运行时环境规范版本 |
12 | java.specification.vendor | Java 运行时环境规范供应商 |
13 | java.specification.name | Java 运行时环境规范名称 |
14 | java.class.version | Java 类格式版本号 |
15 | java.class.path | Java 类路径 |
16 | java.library.path | 加载库时搜索的路径列表 |
17 | java.io.tmpdir | 默认的临时文件路径 |
18 | java.compiler | 要使用的 JIT 编译器的名称 |
19 | java.ext.dirs | 一个或多个扩展目录的路径 |
20 | os.name | 操作系统的名称 |
21 | os.arch | 操作系统的架构 |
22 | os.version | 操作系统的版本 |
23 | file.separator | 文件分隔符(在 UNIX 系统中是“/”) |
24 | path.separator | 路径分隔符(在 UNIX 系统中是“:”) |
25 | line.separator | 行分隔符(在 UNIX 系统中是“/n”) |
26 | user.name | 用户的账户名称 |
27 | user.home | 用户的主目录 |
28 | user.dir | 用户的当前工作目录 |
System.out.println(
"Java运行环境的版本:"
+ System.getProperty(
"java.version"
));
System.out.println(
"Java运行环境的生产商:"
+ System.getProperty(
"java.vendor"
));
System.out.println(
"Java的安装路径:"
+ System.getProperty(
"java.home"
));
System.out.println(
"虚拟机实现的版本:"
+ System.getProperty(
"java.vm.version"
));
System.out.println(
"虚拟机实现的生产商:"
+ System.getProperty(
"java.vm.vendor"
));
System.out.println(
"默认的临时文件路径:"
+ System.getProperty(
"java.io.tmpdir"
));
System.out.println(
"用户的账户名称:"
+ System.getProperty(
"user.name"
));
System.out.println(
"当前用户工作目录:"
+ System.getProperty(
"user.dir"
));
System.out.println(
"用户的home路径:"
+ System.getProperty(
"user.home"
));
System.out.println(
"操作系统的名称:"
+ System.getProperty(
"os.name"
));
System.out.println(
"操作系统的版本:"
+ System.getProperty(
"os.version"
));
System.out.println(
"操作系统的架构:"
+ System.getProperty(
"os.arch"
));
System.out.println(
"运行环境规范的名称:"
+ System.getProperty(
"java.specification.name"
));
System.out.println(
"Java类格式化的版本号:"
+ System.getProperty(
"java.class.version"
));
System.out.println(
"类所在的路径:"
+ System.getProperty(
"java.class.path"
));
当然还可以通过System.setProperty方法set值,如:System.setProperty("jdbc.drivers","aaa.bbb.ccc");
System.setProperty(name, value);
如果从tomcat的conf目录下找到加载:代码如下:
if (is == null) { //从tomcat的conf目录下找到catalina.properties文件加载
try {
File home = new File(Bootstrap.getCatalinaBase());
File conf = new File(home, "conf");
File propsFile = new File(conf, "catalina.properties");
is = new FileInputStream(propsFile);
} catch (Throwable t) {
handleThrowable(t);
}
}
那么catalina.properties文件内容如下:
# 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.
#
# List of comma-separated packages that start with or equal this string
# 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.jasper.,org.apache.tomcat.
#
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageDefinition unless the
# corresponding RuntimePermission ("defineClassInPackage."+package) has
# been granted.
#
# by default, no packages are restricted for definition, and none of
# the class loaders supplied with the JDK call checkPackageDefinition.
#
package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,\
org.apache.jasper.,org.apache.naming.,org.apache.tomcat.
#
#
# 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 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
#
# Note: Values are enclosed in double quotes ("...") in case either the
# ${catalina.base} path or the ${catalina.home} path contains a comma.
# Because double quotes are used for quoting, the double quote character
# may not appear in a path.
common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${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
#
# Note: Values may be enclosed in double quotes ("...") in case either the
# ${catalina.base} path or the ${catalina.home} path contains a comma.
# Because double quotes are used for quoting, the double quote character
# may not appear in a path.
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:.
#
# Note: Values may be enclosed in double quotes ("...") in case either the
# ${catalina.base} path or the ${catalina.home} path contains a comma.
# Because double quotes are used for quoting, the double quote character
# may not appear in a path.
shared.loader=
# Default list of JAR files that should not be scanned using the JarScanner
# functionality. This is typically used to scan JARs for configuration
# information. JARs that do not contain such information may be excluded from
# the scan to speed up the scanning process. This is the default list. JARs on
# this list are excluded from all scans. The list must be a comma separated list
# of JAR file names.
# The list of JARs to skip may be over-ridden at a Context level for individual
# scan types by configuring a JarScanner with a nested JarScanFilter.
# The JARs listed below include:
# - Tomcat Bootstrap JARs
# - Tomcat API JARs
# - Catalina JARs
# - Jasper JARs
# - Tomcat JARs
# - Common non-Tomcat JARs
# - Test JARs (JUnit, Cobertura and dependencies)
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\
bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\
annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,\
catalina.jar,catalina-ant.jar,catalina-ha.jar,catalina-storeconfig.jar,\
catalina-tribes.jar,\
jasper.jar,jasper-el.jar,ecj-*.jar,\
tomcat-api.jar,tomcat-util.jar,tomcat-util-scan.jar,tomcat-coyote.jar,\
tomcat-dbcp.jar,tomcat-jni.jar,tomcat-websocket.jar,\
tomcat-i18n-en.jar,tomcat-i18n-es.jar,tomcat-i18n-fr.jar,tomcat-i18n-ja.jar,\
tomcat-juli-adapters.jar,catalina-jmx-remote.jar,catalina-ws.jar,\
tomcat-jdbc.jar,\
tools.jar,\
commons-beanutils*.jar,commons-codec*.jar,commons-collections*.jar,\
commons-dbcp*.jar,commons-digester*.jar,commons-fileupload*.jar,\
commons-httpclient*.jar,commons-io*.jar,commons-lang*.jar,commons-logging*.jar,\
commons-math*.jar,commons-pool*.jar,\
jstl.jar,taglibs-standard-spec-*.jar,\
geronimo-spec-jaxrpc*.jar,wsdl4j*.jar,\
ant.jar,ant-junit*.jar,aspectj*.jar,jmx.jar,h2*.jar,hibernate*.jar,httpclient*.jar,\
jmx-tools.jar,jta*.jar,log4j*.jar,mail*.jar,slf4j*.jar,\
xercesImpl.jar,xmlParserAPIs.jar,xml-apis.jar,\
junit.jar,junit-*.jar,ant-launcher.jar,\
cobertura-*.jar,asm-*.jar,dom4j-*.jar,icu4j-*.jar,jaxen-*.jar,jdom-*.jar,\
jetty-*.jar,oro-*.jar,servlet-api-*.jar,tagsoup-*.jar,xmlParserAPIs-*.jar,\
xom-*.jar
# Default list of JAR files that should be scanned that overrides the default
# jarsToSkip list above. This is typically used to include a specific JAR that
# has been excluded by a broad file name pattern in the jarsToSkip list.
# The list of JARs to scan may be over-ridden at a Context level for individual
# scan types by configuring a JarScanner with a nested JarScanFilter.
tomcat.util.scan.StandardJarScanFilter.jarsToScan=\
log4j-web*.jar,log4j-taglib*.jar,log4javascript*.jar,slf4j-taglib*.jar
# 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
# This system property is deprecated. Use the relaxedPathChars relaxedQueryChars
# attributes of the Connector instead. These attributes permit a wider range of
# characters to be configured as valid.
# Allow for changes to HTTP request validation
# WARNING: Using this option may expose the server to CVE-2016-6816
#tomcat.util.http.parser.HttpParser.requestTargetAllow=|
其中包含了 common.loader,
server.loader,
shared.loader,
tomcat.util.scan.StandardJarScanFilter.jarsToSkip,
tomcat.util.scan.StandardJarScanFilter.jarsToScan,
tomcat.util.buf.StringCache.byte.enabled,
这些key值,在调用loadProperties方法的时候都会加载存储在Properties properties里。
${catalina.base}:
catalina.home指向公用信息的位置,就是bin和lib的父目录。
catalina.base指向每个Tomcat目录私有信息的位置,就是conf、logs、temp、webapps和work的父目录。
而设置 catalina.base的值和catalina.home的值是在 tomcat\bin\catalina.bat文件中catalina.base设置方法。
catalina.bat文件里面设置catalina.base部分代码如下:
rem Guess CATALINA_HOME if not defined
set "CURRENT_DIR=%cd%"
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome
2、Thread.currentThread().setContextClassLoader(catalinaLoader);
主要作用是把catalinaLoader设置为Tomcat主线程的上下文类加载器。
3、SecurityClassLoad.securityClassLoad(catalinaLoader);线程安全的加载class(类)
SecurityClassLoad类:
public static void securityClassLoad(ClassLoader loader) throws Exception {
securityClassLoad(loader, true);
}
static void securityClassLoad(ClassLoader loader, boolean requireSecurityManager) throws Exception {
if (requireSecurityManager && System.getSecurityManager() == null) {
return;
}
loadCorePackage(loader);
loadCoyotePackage(loader);
loadLoaderPackage(loader);
loadRealmPackage(loader);
loadServletsPackage(loader);
loadSessionPackage(loader);
loadUtilPackage(loader);
loadValvesPackage(loader);
loadWebResourcesPackage(loader);
loadJavaxPackage(loader);
loadConnectorPackage(loader);
loadTomcatPackage(loader);
}
private static final void loadCorePackage(ClassLoader loader) throws Exception {
final String basePackage = "org.apache.catalina.core.";
loader.loadClass(basePackage + "AccessLogAdapter");
loadAnonymousInnerClasses(loader, basePackage + "ApplicationContextFacade");//加载匿名内部类
loader.loadClass(basePackage + "ApplicationDispatcher$PrivilegedForward");
loader.loadClass(basePackage + "ApplicationDispatcher$PrivilegedInclude");
loader.loadClass(basePackage + "AsyncContextImpl");
loader.loadClass(basePackage + "AsyncContextImpl$DebugException");
loadAnonymousInnerClasses(loader, basePackage + "AsyncContextImpl");
loader.loadClass(basePackage + "AsyncListenerWrapper");
loader.loadClass(basePackage + "ContainerBase$PrivilegedAddChild");
loadAnonymousInnerClasses(loader, basePackage + "DefaultInstanceManager");
loader.loadClass(basePackage + "DefaultInstanceManager$AnnotationCacheEntry");
loader.loadClass(basePackage + "DefaultInstanceManager$AnnotationCacheEntryType");
loader.loadClass(basePackage + "ApplicationHttpRequest$AttributeNamesEnumerator");
}
loadCorePackage 加载org.apache.catalina.core.路径下的类包括 AccessLogAdapter,ApplicationContextFacade...
4.使用反射调用了org.apache.catalina.startup.Catalina类的构造方法。
// 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.getConstructor().newInstance();
5.使用Method反射调用org.apache.catalina.startup.Catalina类的setParentClassLoader方法并且参数是sharedLoader。
// 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);
上一篇: php如何实现汉字转utf8
推荐阅读
-
Tomcat源码分析 (六)----- Tomcat 启动过程(一)
-
Bootstrap初始化过程源码分析--netty客户端的启动
-
Tomcat初始化源码流程分析(图解及源码注释) (一)
-
SpringBoot内置tomcat启动原理、以及SpringBoot初始化Servlet的源码分析
-
Tomcat8源码分析系列-启动分析(一) Lifecycle
-
Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析
-
Tomcat源码分析 (六)----- Tomcat 启动过程(一)
-
Bootstrap初始化过程源码分析--netty客户端的启动
-
Tomcat源码分析(一)--初始化init(Bootstrap启动)